Compare commits
7 Commits
foundryvtt
...
v1.5
Author | SHA1 | Date | |
---|---|---|---|
773b3756a6 | |||
d57cdc2af4 | |||
f2d1879135 | |||
ea7132468d | |||
2391fbc4bc | |||
0d2bb2d9a3 | |||
7198eb621d |
2
.gitignore
vendored
@ -1,5 +1,5 @@
|
||||
.vscode/settings.json
|
||||
.idea
|
||||
todo.txt
|
||||
todo.md
|
||||
/.vscode
|
||||
/ignored/
|
||||
|
1
foundryvtt-reve-de-dragon
Symbolic link
@ -0,0 +1 @@
|
||||
foundryvtt-reve-de-dragon
|
Before Width: | Height: | Size: 8.2 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 7.0 KiB |
Before Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 9.6 KiB |
Before Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 7.0 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 8.1 KiB |
Before Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 8.0 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 7.8 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 8.0 KiB |
Before Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 6.2 KiB |
@ -15,19 +15,17 @@
|
||||
"TypeNombreastral": "Nombre astral",
|
||||
"TypeTarot": "Carte de tarot",
|
||||
"TypeCasetmr": "TMR spéciale",
|
||||
"TypeRencontre": "Rencontre TMR",
|
||||
"TypeRencontrestmr": "Rencontre TMR",
|
||||
"TypeMunition": "Munition",
|
||||
"TypeMonnaie": "Monnaie",
|
||||
"TypeHerbe": "Herbe ou plante",
|
||||
"TypeIngredient": "Ingrédient",
|
||||
"TypeFaune": "Faune",
|
||||
"TypeLivre": "Livre",
|
||||
"TypePotion": "Potion",
|
||||
"TypeArme": "Arme",
|
||||
"TypeArmure": "Armure",
|
||||
"TypeConteneur": "Conteneur",
|
||||
"TypeNourritureboisson": "Nourriture & boisson",
|
||||
"TypeService": "Services/Boutique",
|
||||
"TypeChant": "Chant",
|
||||
"TypeDanse": "Danse",
|
||||
"TypeMusique": "Musique",
|
||||
@ -43,9 +41,7 @@
|
||||
"TypeOmbre": "Ombre de Thanatos",
|
||||
"TypeSouffle": "Souffle de Dragon",
|
||||
"TypeTete": "Tête de Dragon",
|
||||
"TypePossession": "Possession",
|
||||
"TypeSortreserve": "Sort en réserve",
|
||||
"TypeExtraitpoetique": "Extrait poetique"
|
||||
"TypePossession": "Possession"
|
||||
},
|
||||
"EFFECT": {
|
||||
"StatusStunned": "Sonné",
|
||||
|
@ -1,9 +1,15 @@
|
||||
import { RdDActorSheet } from "./actor-sheet.js";
|
||||
|
||||
/**
|
||||
* Extend the basic ActorSheet with some very simple modifications
|
||||
* @extends {ActorSheet}
|
||||
*/
|
||||
|
||||
import { HtmlUtility } from "./html-utility.js";
|
||||
import { RdDUtility } from "./rdd-utility.js";
|
||||
import { RdDActorSheet } from "./actor-sheet.js";
|
||||
import { RdDCarac } from "./rdd-carac.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class RdDActorCreatureSheet extends RdDActorSheet {
|
||||
|
||||
/** @override */
|
||||
@ -14,28 +20,51 @@ export class RdDActorCreatureSheet extends RdDActorSheet {
|
||||
width: 640,
|
||||
height: 720,
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }],
|
||||
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }]
|
||||
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }]
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async getData() {
|
||||
let formData = await super.getData();
|
||||
console.log("Creature : ", formData);
|
||||
formData.calc = {
|
||||
caracTotal: RdDCarac.computeTotal(formData.data.carac),
|
||||
resumeBlessures: this.actor.computeResumeBlessure(formData.data.blessures),
|
||||
encTotal: await this.actor.computeEncombrementTotalEtMalusArmure(),
|
||||
surEncombrementMessage: this.actor.getMessageSurEncombrement()
|
||||
}
|
||||
|
||||
RdDUtility.filterItemsPerTypeForSheet(formData);
|
||||
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.objets);
|
||||
formData.conteneurs = RdDUtility.conteneursRacine(formData.conteneurs);
|
||||
|
||||
console.log("Creature : ", this.objetVersConteneur, formData);
|
||||
|
||||
return formData;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
HtmlUtility._showControlWhen($(".gm-only"), game.user.isGM);
|
||||
|
||||
// Everything below here is only needed if the sheet is editable
|
||||
if (!this.options.editable) return;
|
||||
|
||||
// On competence change
|
||||
this.html.find('.creature-carac').change(async event => {
|
||||
html.find('.creature-carac').change(async event => {
|
||||
let compName = event.currentTarget.attributes.compname.value;
|
||||
this.actor.updateCreatureCompetence(compName, "carac_value", parseInt(event.target.value));
|
||||
});
|
||||
this.html.find('.creature-niveau').change(async event => {
|
||||
html.find('.creature-niveau').change(async event => {
|
||||
let compName = event.currentTarget.attributes.compname.value;
|
||||
this.actor.updateCreatureCompetence(compName, "niveau", parseInt(event.target.value));
|
||||
});
|
||||
this.html.find('.creature-dommages').change(async event => {
|
||||
html.find('.creature-dommages').change(async event => {
|
||||
let compName = event.currentTarget.attributes.compname.value;
|
||||
this.actor.updateCreatureCompetence(compName, "dommages", parseInt(event.target.value));
|
||||
});
|
||||
|
@ -1,6 +1,14 @@
|
||||
import { RdDActorSheet } from "./actor-sheet.js";
|
||||
/**
|
||||
* Extend the basic ActorSheet with some very simple modifications
|
||||
* @extends {ActorSheet}
|
||||
*/
|
||||
|
||||
export class RdDActorEntiteSheet extends RdDActorSheet {
|
||||
import { HtmlUtility } from "./html-utility.js";
|
||||
import { Misc } from "./misc.js";
|
||||
import { RdDUtility } from "./rdd-utility.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class RdDActorEntiteSheet extends ActorSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
@ -10,31 +18,129 @@ export class RdDActorEntiteSheet extends RdDActorSheet {
|
||||
width: 640,
|
||||
height: 720,
|
||||
tabs: [{navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac"}],
|
||||
dragDrop: [{dragSelector: ".item-list .item", dropSelector: undefined}]
|
||||
dragDrop: [{dragSelector: ".item-list .item", dropSelector: null}]
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async getData() {
|
||||
const objectData = Misc.data(this.object);
|
||||
let formData = {
|
||||
title: this.title,
|
||||
id: objectData.id,
|
||||
type: objectData.type,
|
||||
img: objectData.img,
|
||||
name: objectData.name,
|
||||
// actor: this.object,
|
||||
editable: this.isEditable,
|
||||
cssClass: this.isEditable ? "editable" : "locked",
|
||||
data: foundry.utils.deepClone(Misc.templateData(this.object)),
|
||||
effects: this.object.effects.map(e => foundry.utils.deepClone(e.data)),
|
||||
// items: items,
|
||||
limited: this.object.limited,
|
||||
options: this.options,
|
||||
owner: this.document.isOwner,
|
||||
itemsByType: Misc.classify(this.object.items.map(i => foundry.utils.deepClone(i.data))),
|
||||
};
|
||||
|
||||
formData.options.isGM = game.user.isGM;
|
||||
RdDUtility.filterItemsPerTypeForSheet(formData);
|
||||
|
||||
|
||||
return formData;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
HtmlUtility._showControlWhen($(".gm-only"), game.user.isGM);
|
||||
|
||||
// Everything below here is only needed if the sheet is editable
|
||||
if (!this.options.editable) return;
|
||||
|
||||
// Update Inventory Item
|
||||
html.find('.item-edit').click(event => {
|
||||
const li = $(event.currentTarget).parents(".item");
|
||||
const item = this.actor.getEmbeddedDocument('Item', li.data("itemId"));
|
||||
item.sheet.render(true);
|
||||
});
|
||||
|
||||
// Delete Inventory Item
|
||||
html.find('.item-delete').click(event => {
|
||||
const li = $(event.currentTarget).parents(".item");
|
||||
this.actor.deleteEmbeddedDocuments('Item', [li.data("itemId")]);
|
||||
li.slideUp(200, () => this.render(false));
|
||||
});
|
||||
|
||||
// Roll Carac
|
||||
html.find('.carac-label a').click(async event => {
|
||||
let caracName = event.currentTarget.attributes.name.value;
|
||||
this.actor.rollCarac( caracName.toLowerCase() );
|
||||
});
|
||||
|
||||
// On competence change
|
||||
this.html.find('.creature-carac').change(async event => {
|
||||
html.find('.creature-carac').change(async event => {
|
||||
let compName = event.currentTarget.attributes.compname.value;
|
||||
this.actor.updateCreatureCompetence( compName, "carac_value", parseInt(event.target.value) );
|
||||
} );
|
||||
this.html.find('.creature-niveau').change(async event => {
|
||||
html.find('.creature-niveau').change(async event => {
|
||||
let compName = event.currentTarget.attributes.compname.value;
|
||||
this.actor.updateCreatureCompetence( compName, "niveau", parseInt(event.target.value) );
|
||||
} );
|
||||
this.html.find('.creature-dommages').change(async event => {
|
||||
html.find('.creature-dommages').change(async event => {
|
||||
let compName = event.currentTarget.attributes.compname.value;
|
||||
this.actor.updateCreatureCompetence( compName, "dommages", parseInt(event.target.value) );
|
||||
} );
|
||||
|
||||
// Roll Skill
|
||||
html.find('.competence-label a').click(async event => {
|
||||
let compName = event.currentTarget.text;
|
||||
this.actor.rollCompetence( compName );
|
||||
});
|
||||
|
||||
html.find('.endurance-plus').click(event => {
|
||||
this.actor.santeIncDec("endurance", 1);
|
||||
this.render(true);
|
||||
});
|
||||
html.find('.endurance-moins').click(event => {
|
||||
this.actor.santeIncDec("endurance", -1);
|
||||
this.render(true);
|
||||
});
|
||||
|
||||
html.find('.encaisser-direct').click(event => {
|
||||
this.actor.encaisser();
|
||||
});
|
||||
|
||||
html.find('.remise-a-neuf').click(event => {
|
||||
if (game.user.isGM) {
|
||||
this.actor.remiseANeuf();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
setPosition(options = {}) {
|
||||
const position = super.setPosition(options);
|
||||
const sheetHeader = this.element.find(".sheet-header");
|
||||
const sheetTabs = this.element.find(".sheet-tabs");
|
||||
const sheetBody = this.element.find(".sheet-body");
|
||||
const bodyHeight = position.height - sheetHeader[0].clientHeight - sheetTabs[0].clientHeight;
|
||||
sheetBody.css("height", bodyHeight);
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
_updateObject(event, formData) {
|
||||
// Update the Actor
|
||||
return this.object.update(formData);
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,15 @@
|
||||
/**
|
||||
* Extend the basic ActorSheet with some very simple modifications
|
||||
* @extends {ActorSheet}
|
||||
*/
|
||||
|
||||
import { RdDUtility } from "./rdd-utility.js";
|
||||
import { RdDActorSheet } from "./actor-sheet.js";
|
||||
import { HtmlUtility } from "./html-utility.js";
|
||||
import { Misc } from "./misc.js";
|
||||
import { RdDSheetUtility } from "./rdd-sheet-utility.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class RdDActorVehiculeSheet extends RdDActorSheet {
|
||||
export class RdDActorVehiculeSheet extends ActorSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
@ -14,26 +21,145 @@ export class RdDActorVehiculeSheet extends RdDActorSheet {
|
||||
width: 640,
|
||||
height: 720,
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }],
|
||||
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }]
|
||||
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }]
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async getData() {
|
||||
const objectData = Misc.data(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",
|
||||
data: foundry.utils.deepClone(Misc.templateData(this.object)),
|
||||
effects: this.object.effects.map(e => foundry.utils.deepClone(e.data)),
|
||||
limited: this.object.limited,
|
||||
options: this.options,
|
||||
owner: this.document.isOwner,
|
||||
itemsByType: Misc.classify(this.object.items.map(i => foundry.utils.deepClone(i.data))),
|
||||
};
|
||||
|
||||
RdDUtility.filterItemsPerTypeForSheet(formData);
|
||||
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.objets);
|
||||
formData.conteneurs = RdDUtility.conteneursRacine(formData.conteneurs);
|
||||
|
||||
formData.options.isGM = game.user.isGM;
|
||||
|
||||
formData.calc = {
|
||||
encTotal: await this.actor.computeEncombrementTotalEtMalusArmure(),
|
||||
surEncombrementMessage: this.actor.getMessageSurEncombrement()
|
||||
}
|
||||
|
||||
console.log("DATA", formData);
|
||||
|
||||
return formData;
|
||||
}
|
||||
|
||||
async computeMalusArmure() {
|
||||
// pas de malus armure
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
async _onDropItem(event, dragData) {
|
||||
const destItemId = $(event.target)?.closest('.item').attr('data-item-id');
|
||||
const dropParams = RdDSheetUtility.prepareItemDropParameters(destItemId, this.actor.id, dragData, this.objetVersConteneur);
|
||||
const callSuper = await this.actor.processDropItem(dropParams);
|
||||
if (callSuper) {
|
||||
await super._onDropItem(event, dragData)
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async createItem(name, type) {
|
||||
await this.actor.createEmbeddedDocuments('Item', [{ name: name, type: type }], { renderSheet: true });
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async monnaieIncDec(id, value) {
|
||||
let monnaie = this.getMonnaie(id);
|
||||
if (monnaie) {
|
||||
const quantite = Math.max(0, Misc.templateData(monnaie).quantite + value);
|
||||
await this.updateEmbeddedDocuments('Item', [{ _id: monnaie.id, 'data.quantite': quantite }]);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
HtmlUtility._showControlWhen($(".gm-only"), game.user.isGM);
|
||||
|
||||
// Everything below here is only needed if the sheet is editable
|
||||
if (!this.options.editable) return;
|
||||
|
||||
this.html.find('.resistance-moins').click(async event => {
|
||||
this.actor.vehicleIncDec("resistance", -1);
|
||||
// Update Inventory Item
|
||||
html.find('.item-edit').click(async event => {
|
||||
const item = RdDSheetUtility.getItem(event, this.actor);
|
||||
item.sheet.render(true);
|
||||
});
|
||||
this.html.find('.resistance-plus').click(async event => {
|
||||
this.actor.vehicleIncDec("resistance", 1);
|
||||
// Delete Inventory Item
|
||||
html.find('.item-delete').click(async event => {
|
||||
const li = RdDSheetUtility.getEventElement(event);
|
||||
RdDUtility.confirmerSuppression(this, li);
|
||||
});
|
||||
this.html.find('.structure-moins').click(async event => {
|
||||
this.actor.vehicleIncDec("structure", -1);
|
||||
html.find('.item-vendre').click(async event => {
|
||||
const item = RdDSheetUtility.getItem(event, this.actor);
|
||||
item?.proposerVente();
|
||||
});
|
||||
this.html.find('.structure-plus').click(async event => {
|
||||
this.actor.vehicleIncDec("structure", 1);
|
||||
html.find('.item-montrer').click(async event => {
|
||||
const item = RdDSheetUtility.getItem(event, this.actor);
|
||||
item?.postItem();
|
||||
});
|
||||
|
||||
html.find('.item-action').click(async event => {
|
||||
const item = RdDSheetUtility.getItem(event, this.actor);
|
||||
this.actor.actionItem(item);
|
||||
});
|
||||
|
||||
html.find('.creer-un-objet').click(async event => {
|
||||
RdDUtility.selectObjetType(this);
|
||||
});
|
||||
html.find('#nettoyer-conteneurs').click(async event => {
|
||||
this.actor.nettoyerConteneurs();
|
||||
});
|
||||
|
||||
html.find('.monnaie-plus').click(async event => {
|
||||
this.actor.monnaieIncDec(RdDSheetUtility.getItemId(event), 1);
|
||||
});
|
||||
html.find('.monnaie-moins').click(async event => {
|
||||
this.actor.monnaieIncDec(RdDSheetUtility.getItemId(event), -1);
|
||||
});
|
||||
|
||||
// Display info about queue
|
||||
html.find('.conteneur-name a').click((event) => {
|
||||
RdDUtility.toggleAfficheContenu(RdDSheetUtility.getItemId(event));
|
||||
this.render(true);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
setPosition(options = {}) {
|
||||
const position = super.setPosition(options);
|
||||
const sheetHeader = this.element.find(".sheet-header");
|
||||
const sheetTabs = this.element.find(".sheet-tabs");
|
||||
const sheetBody = this.element.find(".sheet-body");
|
||||
const bodyHeight = position.height - sheetHeader[0].clientHeight - sheetTabs[0].clientHeight;
|
||||
sheetBody.css("height", bodyHeight);
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
_updateObject(event, formData) {
|
||||
// Update the Actor
|
||||
return this.object.update(formData);
|
||||
}
|
||||
}
|
||||
|
2307
module/actor.js
@ -1,6 +1,7 @@
|
||||
import { Misc } from "./misc.js";
|
||||
import { SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
|
||||
|
||||
export const MESSAGE_DATA = 'message-data';
|
||||
|
||||
/**
|
||||
* Class providing helper methods to get the list of users, and
|
||||
@ -18,50 +19,61 @@ export class ChatUtility {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static notifyUser(userId, level = 'info', message) {
|
||||
const socketData = {
|
||||
const data = {
|
||||
userId: userId, level: level, message: message
|
||||
};
|
||||
if (game.user.id == userId) {
|
||||
ChatUtility.onNotifyUser(socketData);
|
||||
ChatUtility.onNotifyUser(data);
|
||||
}
|
||||
else {
|
||||
game.socket.emit(SYSTEM_SOCKET_ID, {
|
||||
msg: "msg_user_ui_notifications", data: socketData
|
||||
msg: "msg_user_ui_notifications", data: data
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static onNotifyUser(socketData) {
|
||||
if (game.user.id == socketData.userId) {
|
||||
switch (socketData.level) {
|
||||
case 'warn': ui.notifications.warn(socketData.message); break;
|
||||
case 'error': ui.notifications.error(socketData.message); break;
|
||||
default: ui.notifications.info(socketData.message); break;
|
||||
static onNotifyUser(data) {
|
||||
if (game.user.id == data.userId) {
|
||||
switch (data.level) {
|
||||
case 'warn': ui.notifications.warn(data.message); break;
|
||||
case 'error': ui.notifications.error(data.message); break;
|
||||
default: ui.notifications.info(data.message); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static onRemoveMessages(socketData) {
|
||||
static onRemoveMessages(data) {
|
||||
if (Misc.isUniqueConnectedGM()) {
|
||||
if (socketData.part) {
|
||||
const toDelete = game.messages.filter(it => it.content.includes(socketData.part));
|
||||
if (data.part) {
|
||||
const toDelete = game.messages.filter(it => it.data.content.includes(data.part));
|
||||
toDelete.forEach(it => it.delete());
|
||||
}
|
||||
if (socketData.messageId) {
|
||||
game.messages.get(socketData.messageId)?.delete();
|
||||
if (data.messageId) {
|
||||
game.messages.get(data.messageId)?.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static onRemoveMessages(data) {
|
||||
if (Misc.isUniqueConnectedGM()) {
|
||||
if (data.part) {
|
||||
const toDelete = game.messages.filter(it => it.data.content.includes(data.part));
|
||||
toDelete.forEach(it => it.delete());
|
||||
}
|
||||
if (data.messageId) {
|
||||
game.messages.get(data.messageId)?.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
|
||||
static removeMessages(socketData) {
|
||||
static removeMessages(data) {
|
||||
if (Misc.isUniqueConnectedGM()) {
|
||||
ChatUtility.onRemoveMessages(socketData);
|
||||
ChatUtility.onRemoveMessages(data);
|
||||
}
|
||||
else {
|
||||
game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_delete_chat_message", data: socketData });
|
||||
game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_delete_chat_message", data: data });
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,7 +141,7 @@ export class ChatUtility {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getUsers(filter) {
|
||||
return game.users.filter(filter).map(user => user.id);
|
||||
return Misc.getUsers().filter(filter).map(user => user.data._id);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -142,17 +154,17 @@ export class ChatUtility {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static handleGMChatMessage(socketData) {
|
||||
console.log("blindMessageToGM", socketData);
|
||||
static handleGMChatMessage(data) {
|
||||
console.log("blindMessageToGM", data);
|
||||
if (game.user.isGM) { // message privé pour GM only
|
||||
socketData.user = game.user.id;
|
||||
ChatMessage.create(socketData);
|
||||
data.user = game.user.id;
|
||||
ChatMessage.create(data);
|
||||
}
|
||||
}
|
||||
|
||||
static async setMessageData(chatMessage, key, flag) {
|
||||
if (flag) {
|
||||
await chatMessage.setFlag(SYSTEM_RDD, key, JSON.stringify(flag));
|
||||
static async setMessageData(chatMessage, key, data) {
|
||||
if (data) {
|
||||
await chatMessage.setFlag(SYSTEM_RDD, key, JSON.stringify(data));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
export const SYSTEM_RDD = 'foundryvtt-reve-de-dragon';
|
||||
export const SYSTEM_SOCKET_ID = 'system.foundryvtt-reve-de-dragon';
|
||||
export const LOG_HEAD = 'RdD | ';
|
||||
|
||||
export const HIDE_DICE = 'hide';
|
||||
export const SHOW_DICE = 'show';
|
||||
|
@ -1,127 +0,0 @@
|
||||
import { SYSTEM_RDD } from "./constants.js";
|
||||
import { Grammar } from "./grammar.js";
|
||||
|
||||
|
||||
const LATEST_USED_JOURNAL_ID = "chronologie-dernier-journal";
|
||||
|
||||
export class DialogChronologie extends Dialog {
|
||||
|
||||
static init() {
|
||||
game.settings.register(SYSTEM_RDD, LATEST_USED_JOURNAL_ID, {
|
||||
name: "Dernier article de journal utilisé pour enregistrer la chronologie",
|
||||
scope: "client",
|
||||
config: false,
|
||||
default: "",
|
||||
type: String
|
||||
});
|
||||
}
|
||||
static async create() {
|
||||
const dateRdD = game.system.rdd.calendrier.getCalendrier();
|
||||
const dialogData = {
|
||||
auteur: game.user.name,
|
||||
isGM: game.user.isGM,
|
||||
information: "",
|
||||
journalId: game.settings.get(SYSTEM_RDD, LATEST_USED_JOURNAL_ID),
|
||||
journaux: game.journal.filter(it => it.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)),
|
||||
dateRdD: dateRdD,
|
||||
jourRdD: dateRdD.jour +1,
|
||||
heureRdD: game.system.rdd.calendrier.getCurrentHeure(),
|
||||
dateReel: DialogChronologie.getCurrentDateTime()
|
||||
};
|
||||
const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-chronologie.html", dialogData);
|
||||
const dialog = new DialogChronologie(html);
|
||||
dialog.render(true);
|
||||
}
|
||||
|
||||
constructor(html) {
|
||||
const options = {
|
||||
classes: ["DialogChronologie"],
|
||||
width: 500,
|
||||
height: 'fit-content',
|
||||
'z-index': 99999
|
||||
};
|
||||
const conf = {
|
||||
title: "Chronologie",
|
||||
content: html,
|
||||
buttons: {
|
||||
ajout: { label: "Ajouter", callback: it => this.ajouter() },
|
||||
}
|
||||
};
|
||||
super(conf, options);
|
||||
}
|
||||
|
||||
static getCurrentDateTime() {
|
||||
return new Date().toLocaleString("sv-SE", {
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit"
|
||||
}).replace(" ", "T");
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
this.html = html;
|
||||
}
|
||||
|
||||
async ajouter() {
|
||||
await this.forceValidation();
|
||||
const { journalId, journalEntry } = this.findJournal();
|
||||
// ajouter à la page ou créer une page
|
||||
this.addContentToJournal(journalEntry, await this.prepareChronologieEntry());
|
||||
|
||||
this.storeLatestUsedJournalEntry(journalId);
|
||||
}
|
||||
|
||||
async forceValidation() {
|
||||
await this.html.find("form.rdddialogchrono :input").change();
|
||||
}
|
||||
|
||||
findJournal() {
|
||||
const journalId = this.html.find("form.rdddialogchrono :input[name='journalId']").val();
|
||||
const journalEntry = game.journal.get(journalId);
|
||||
return { journalId, journalEntry };
|
||||
}
|
||||
|
||||
async prepareChronologieEntry() {
|
||||
return await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/chronologie-entry.html", this.extractJournalParameters());
|
||||
}
|
||||
|
||||
extractJournalParameters() {
|
||||
return {
|
||||
auteur: this.html.find("form.rdddialogchrono :input[name='auteur']").val(),
|
||||
information: this.html.find("form.rdddialogchrono :input[name='information']").val(),
|
||||
dateRdD: {
|
||||
jour: this.html.find("form.rdddialogchrono :input[name='jourRdD']").val(),
|
||||
moisRdD: this.html.find("form.rdddialogchrono :input[name='dateRdD.moisRdD.key']").val(),
|
||||
annee: this.html.find("form.rdddialogchrono :input[name='dateRdD.annee']").val()
|
||||
},
|
||||
heureRdD: this.html.find("form.rdddialogchrono :input[name='heureRdD']").val(),
|
||||
dateReel: this.html.find("form.rdddialogchrono :input[name='dateReel']").val().replace('T', ' ')
|
||||
}
|
||||
}
|
||||
|
||||
addContentToJournal(journalEntry, content) {
|
||||
let page = journalEntry.pages.find(p => p.type == 'text' && Grammar.equalsInsensitive(p.name, 'Chronologie'));
|
||||
if (page) {
|
||||
page.update({ 'text.content': content + '\n' + page.text.content });
|
||||
}
|
||||
else {
|
||||
journalEntry.createEmbeddedDocuments('JournalEntryPage', [this.newPageChronologie(content)]);
|
||||
}
|
||||
}
|
||||
|
||||
newPageChronologie(content) {
|
||||
return new JournalEntryPage({
|
||||
name: 'Chronologie',
|
||||
type: 'text',
|
||||
title: { show: true, level: 1 },
|
||||
text: { content: content, format: 1 }
|
||||
});
|
||||
}
|
||||
|
||||
storeLatestUsedJournalEntry(journalId) {
|
||||
game.settings.set(SYSTEM_RDD, LATEST_USED_JOURNAL_ID, journalId);
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
import { ChatUtility } from "./chat-utility.js";
|
||||
import { HtmlUtility } from "./html-utility.js";
|
||||
import { RdDItemSigneDraconique } from "./item-signedraconique.js";
|
||||
import { Misc } from "./misc.js";
|
||||
import { TMRUtility } from "./tmr-utility.js";
|
||||
|
||||
export class DialogCreateSigneDraconique extends Dialog {
|
||||
@ -9,13 +10,12 @@ export class DialogCreateSigneDraconique extends Dialog {
|
||||
const signe = await RdDItemSigneDraconique.randomSigneDraconique({ephemere: true});
|
||||
let dialogData = {
|
||||
signe: signe,
|
||||
tmrs: TMRUtility.buildSelectionTypesTMR(signe.system.typesTMR),
|
||||
actors: game.actors.filter(actor => actor.isPersonnage() && actor.isHautRevant())
|
||||
.map(actor => ({
|
||||
id: actor.id,
|
||||
name: actor.name,
|
||||
selected: true
|
||||
}))
|
||||
tmrs: TMRUtility.listSelectedTMR(signe.data.typesTMR ?? []),
|
||||
actors: game.actors.filter(actor => actor.isHautRevant()).map(actor => {
|
||||
let actorData = duplicate(Misc.data(actor));
|
||||
actorData.selected = actor.hasPlayerOwner;
|
||||
return actorData;
|
||||
})
|
||||
};
|
||||
|
||||
const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-create-signedraconique.html", dialogData);
|
||||
@ -23,11 +23,12 @@ export class DialogCreateSigneDraconique extends Dialog {
|
||||
.render(true);
|
||||
}
|
||||
|
||||
constructor(dialogData, html) {
|
||||
constructor(dialogData, html, callback) {
|
||||
let options = { classes: ["DialogCreateSigneDraconiqueActorsActors"], width: 500, height: 650, 'z-index': 99999 };
|
||||
let conf = {
|
||||
title: "Créer un signe",
|
||||
content: html,
|
||||
default: "Ajouter aux haut-rêvants",
|
||||
buttons: {
|
||||
"Ajouter aux haut-rêvants": { label: "Ajouter aux haut-rêvants", callback: it => { this._onCreerSigneActeurs(); } }
|
||||
}
|
||||
@ -35,94 +36,83 @@ export class DialogCreateSigneDraconique extends Dialog {
|
||||
super(conf, options);
|
||||
this.dialogData = dialogData;
|
||||
}
|
||||
|
||||
|
||||
async _onCreerSigneActeurs() {
|
||||
await this.html.find("[name='signe.system.ephemere']").change();
|
||||
await this.html.find(".signe-xp-sort").change();
|
||||
await $("[name='signe.data.ephemere']").change();
|
||||
await $(".signe-xp-sort").change();
|
||||
this.validerSigne();
|
||||
this.dialogData.actors.filter(it => it.selected)
|
||||
.map(it => game.actors.get(it.id))
|
||||
.forEach(actor => this._createSigneForActor(actor, this.dialogData.signe));
|
||||
this.dialogData.actors.filter(it => it.selected).map(it => game.actors.get(it._id))
|
||||
.forEach(actor => this._createSigneForActor(actor, this.dialogData.signe));
|
||||
}
|
||||
|
||||
|
||||
async _createSigneForActor(actor, signe) {
|
||||
actor.createEmbeddedDocuments("Item", [signe]);
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(actor.name),
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(Misc.data(actor).name),
|
||||
content: await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/chat-signe-draconique-actor.html", {
|
||||
signe: signe,
|
||||
alias: actor.name
|
||||
alias: Misc.data(actor).name
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
validerSigne() {
|
||||
this.dialogData.signe.name = this.html.find("[name='signe.name']").val();
|
||||
this.dialogData.signe.system.valeur.norm = this.html.find("[name='signe.system.valeur.norm']").val();
|
||||
this.dialogData.signe.system.valeur.sign = this.html.find("[name='signe.system.valeur.sign']").val();
|
||||
this.dialogData.signe.system.valeur.part = this.html.find("[name='signe.system.valeur.part']").val();
|
||||
this.dialogData.signe.system.difficulte = this.html.find("[name='signe.system.difficulte']").val();
|
||||
this.dialogData.signe.system.ephemere = this.html.find("[name='signe.system.ephemere']").prop("checked");
|
||||
this.dialogData.signe.system.duree = this.html.find("[name='signe.system.duree']").val();
|
||||
this.dialogData.signe.system.typesTMR = TMRUtility.buildListTypesTMRSelection(this.dialogData.tmrs);
|
||||
this.dialogData.signe.name = $("[name='signe.name']").val();
|
||||
this.dialogData.signe.data.valeur.norm = $("[name='signe.data.valeur.norm']").val();
|
||||
this.dialogData.signe.data.valeur.sign = $("[name='signe.data.valeur.sign']").val();
|
||||
this.dialogData.signe.data.valeur.part = $("[name='signe.data.valeur.part']").val();
|
||||
this.dialogData.signe.data.difficulte = $("[name='signe.data.difficulte']").val();
|
||||
this.dialogData.signe.data.ephemere = $("[name='signe.data.ephemere']").prop("checked");
|
||||
this.dialogData.signe.data.duree = $("[name='signe.data.duree']").val();
|
||||
this.dialogData.signe.data.typesTMR = $(".select-tmr").val();
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
this.html = html;
|
||||
this.setEphemere(this.dialogData.signe.system.ephemere);
|
||||
this.setEphemere(this.dialogData.signe.data.ephemere);
|
||||
html.find(".signe-aleatoire").click(event => this.setSigneAleatoire());
|
||||
html.find("[name='signe.system.ephemere']").change((event) => this.setEphemere(event.currentTarget.checked));
|
||||
html.find("[name='signe.data.ephemere']").change((event) => this.setEphemere(event.currentTarget.checked));
|
||||
html.find(".select-actor").change((event) => this.onSelectActor(event));
|
||||
html.find(".signe-xp-sort").change((event) => this.onValeurXpSort(event));
|
||||
html.find("input.select-actor").change((event) => this.onSelectActor(event));
|
||||
html.find("input.select-tmr").change((event) => this.onSelectTmr(event));
|
||||
}
|
||||
|
||||
async setSigneAleatoire() {
|
||||
const newSigne = await RdDItemSigneDraconique.randomSigneDraconique({ephemere: true});
|
||||
|
||||
this.html.find("[name='signe.name']").val(newSigne.name);
|
||||
this.html.find("[name='signe.system.valeur.norm']").val(newSigne.system.valeur.norm);
|
||||
this.html.find("[name='signe.system.valeur.sign']").val(newSigne.system.valeur.sign);
|
||||
this.html.find("[name='signe.system.valeur.part']").val(newSigne.system.valeur.part);
|
||||
this.html.find("[name='signe.system.difficulte']").val(newSigne.system.difficulte);
|
||||
this.html.find("[name='signe.system.duree']").val(newSigne.system.duree);
|
||||
this.html.find("[name='signe.system.ephemere']").prop("checked", newSigne.system.ephemere);
|
||||
this.dialogData.tmrs = TMRUtility.buildSelectionTypesTMR(newSigne.system.typesTMR);
|
||||
this.dialogData.tmrs.forEach(t => {
|
||||
this.html.find(`[data-tmr-name='${t.name}']`).prop( "checked", t.selected);
|
||||
})
|
||||
this.setEphemere(newSigne.system.ephemere);
|
||||
$("[name='signe.name']").val(newSigne.name);
|
||||
$("[name='signe.data.valeur.norm']").val(newSigne.data.valeur.norm);
|
||||
$("[name='signe.data.valeur.sign']").val(newSigne.data.valeur.sign);
|
||||
$("[name='signe.data.valeur.part']").val(newSigne.data.valeur.part);
|
||||
$("[name='signe.data.difficulte']").val(newSigne.data.difficulte);
|
||||
$("[name='signe.data.duree']").val(newSigne.data.duree);
|
||||
$("[name='signe.data.ephemere']").prop("checked", newSigne.data.ephemere);
|
||||
$(".select-tmr").val(newSigne.data.typesTMR);
|
||||
this.setEphemere(newSigne.data.ephemere);
|
||||
}
|
||||
|
||||
async setEphemere(ephemere) {
|
||||
this.dialogData.signe.system.ephemere = ephemere;
|
||||
HtmlUtility._showControlWhen(this.html.find(".signe-system-duree"), ephemere);
|
||||
this.dialogData.signe.data.ephemere = ephemere;
|
||||
HtmlUtility._showControlWhen($(".signe-data-duree"), ephemere);
|
||||
}
|
||||
|
||||
async onSelectActor(event) {
|
||||
const actorId = this.html.find(event.currentTarget)?.data("actor-id");
|
||||
const actor = this.dialogData.actors.find(it => it.id == actorId);
|
||||
if (actor) {
|
||||
actor.selected = event.currentTarget.checked;
|
||||
}
|
||||
event.preventDefault();
|
||||
const options = event.currentTarget.options;
|
||||
for (var i = 0; i < options.length; i++) { // looping over the options
|
||||
const actorId = options[i].attributes["data-actor-id"].value;
|
||||
const actor = this.dialogData.actors.find(it => it._id == actorId);
|
||||
if (actor) {
|
||||
actor.selected = options[i].selected;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
onSelectTmr(event) {
|
||||
const tmrName = this.html.find(event.currentTarget)?.data("tmr-name");
|
||||
const onTmr = this.tmrs.find(it => it.name == tmrName);
|
||||
if (onTmr){
|
||||
onTmr.selected = event.currentTarget.checked;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
onValeurXpSort(event) {
|
||||
const codeReussite = event.currentTarget.attributes['data-typereussite']?.value ?? 0;
|
||||
const xp = Number(event.currentTarget.value);
|
||||
const oldValeur = this.dialogData.signe.system.valeur;
|
||||
this.dialogData.signe.system.valeur = RdDItemSigneDraconique.calculValeursXpSort(codeReussite, xp, oldValeur);
|
||||
const oldValeur = this.dialogData.signe.data.valeur;
|
||||
this.dialogData.signe.data.valeur = RdDItemSigneDraconique.calculValeursXpSort(codeReussite, xp, oldValeur);
|
||||
}
|
||||
|
||||
}
|
@ -6,43 +6,36 @@ export class DialogFabriquerPotion extends Dialog {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async create(actor, item, dialogConfig) {
|
||||
const min = DialogFabriquerPotion.nombreBrinsMinimum(item);
|
||||
if (item.system.quantite < min) {
|
||||
ui.notifications.warn(`Vous avez ${item.system.quantite} brins de ${item.name}, il en faut au moins ${min} pour faire une potion!`);
|
||||
return;
|
||||
}
|
||||
let potionData = DialogFabriquerPotion.prepareData(actor, item);
|
||||
|
||||
const html = await renderTemplate(dialogConfig.html, potionData);
|
||||
let conf = {
|
||||
title: `Fabriquer une potion de ${potionData.data.categorie}`,
|
||||
content: await renderTemplate(dialogConfig.html, potionData),
|
||||
default: potionData.buttonName,
|
||||
};
|
||||
|
||||
let options = { classes: ["dialogfabriquerpotion"], width: 600, height: 160, 'z-index': 99999 };
|
||||
mergeObject(options, dialogConfig.options ?? {}, { overwrite: true })
|
||||
|
||||
new DialogFabriquerPotion(actor, potionData, html, options).render(true);
|
||||
const dialog = new DialogFabriquerPotion(actor, potionData, conf, options);
|
||||
dialog.render(true);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static prepareData(actor, item) {
|
||||
let potionData = duplicate(item)
|
||||
potionData.nbBrinsSelect = RdDUtility.buildListOptions(
|
||||
DialogFabriquerPotion.nombreBrinsMinimum(item),
|
||||
DialogFabriquerPotion.nombreBrinsOptimal(item));
|
||||
potionData.nbBrins = Math.min(potionData.system.quantite, DialogFabriquerPotion.nombreBrinsOptimal(potionData));
|
||||
potionData.herbebonus = item.system.niveau;
|
||||
let potionData = duplicate(Misc.data(item));
|
||||
potionData.nbBrinsSelect = RdDUtility.buildListOptions(1, potionData.data.quantite);
|
||||
potionData.nbBrins = Math.min(potionData.data.quantite, DialogFabriquerPotion.getNombreBrinOptimal(potionData));
|
||||
potionData.buttonName = "Fabriquer";
|
||||
return potionData;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(actor, potionData, html, options) {
|
||||
const conf = {
|
||||
title: `Fabriquer une potion de ${potionData.system.categorie}`,
|
||||
content: html,
|
||||
default: 'fabriquer',
|
||||
buttons: {
|
||||
'fabriquer': {
|
||||
label: potionData.buttonName, callback: it => this.onFabriquer(html)
|
||||
}
|
||||
constructor(actor, potionData, conf, options) {
|
||||
conf.buttons = {
|
||||
[potionData.buttonName]: {
|
||||
label: potionData.buttonName, callback: it => this.onFabriquer(it)
|
||||
}
|
||||
};
|
||||
|
||||
@ -52,37 +45,27 @@ export class DialogFabriquerPotion extends Dialog {
|
||||
this.potionData = potionData;
|
||||
}
|
||||
|
||||
static getNombreBrinOptimal(herbeData) {
|
||||
switch (herbeData.data.categorie ?? '') {
|
||||
case "Soin": return 12 - herbeData.data.niveau;
|
||||
case "Repos": return 7 - herbeData.data.niveau;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
this.html = html;
|
||||
this.html.find("[name='nbBrins']").change(event => {
|
||||
|
||||
html.find("#nbBrins").change(event => {
|
||||
this.potionData.nbBrins = Misc.toInt(event.currentTarget.value);
|
||||
const brinsManquants = Math.max(0, DialogFabriquerPotion.nombreBrinsOptimal(this.potionData) - this.potionData.nbBrins);
|
||||
this.potionData.herbebonus = Math.max(0, this.potionData.system.niveau - brinsManquants)
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async onFabriquer(html) {
|
||||
await this.html.find("[name='nbBrins']").change();
|
||||
async onFabriquer(it) {
|
||||
await $("#nbBrins").change();
|
||||
this.actor.fabriquerPotion(this.potionData);
|
||||
this.close();
|
||||
}
|
||||
|
||||
static nombreBrinsMinimum(herbeData) {
|
||||
switch (herbeData.system.categorie ?? '') {
|
||||
case "Soin": return 1 + Math.max(0, 12 - 2 * herbeData.system.niveau);
|
||||
case "Repos": return 1 + Math.max(0, 7 - 2 * herbeData.system.niveau);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static nombreBrinsOptimal(herbeData) {
|
||||
switch (herbeData.system.categorie ?? '') {
|
||||
case "Soin": return 12 - herbeData.system.niveau;
|
||||
case "Repos": return 7 - herbeData.system.niveau;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
@ -1,107 +1,93 @@
|
||||
|
||||
import { Misc } from "./misc.js";
|
||||
import { RdDUtility } from "./rdd-utility.js";
|
||||
|
||||
export class DialogItemAchat extends Dialog {
|
||||
|
||||
static preparerAchat(chatButton) {
|
||||
const vendeurId = chatButton.attributes['data-vendeurId']?.value;
|
||||
static async onButtonAcheter(event) {
|
||||
const buttonAcheter = event.currentTarget;
|
||||
if (!buttonAcheter.attributes['data-jsondata']?.value) {
|
||||
ui.notifications.warn("Impossible d'acheter: informations sur l'objet manquantes")
|
||||
return;
|
||||
}
|
||||
const chatMessageIdVente = RdDUtility.findChatMessageId(buttonAcheter);
|
||||
|
||||
const vendeurId = buttonAcheter.attributes['data-vendeurId']?.value;
|
||||
const vendeur = vendeurId ? game.actors.get(vendeurId) : undefined;
|
||||
const acheteur = RdDUtility.getSelectedActor();
|
||||
const json = chatButton.attributes['data-jsondata']?.value;
|
||||
|
||||
if (!acheteur && !vendeur) {
|
||||
ui.notifications.info("Pas d'acheteur ni de vendeur, aucun changement");
|
||||
return undefined;
|
||||
}
|
||||
if (!json) {
|
||||
ui.notifications.warn("Impossible d'acheter: informations sur l'objet manquantes")
|
||||
return undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
return {
|
||||
item: (json ? JSON.parse(json) : undefined),
|
||||
vendeur,
|
||||
acheteur,
|
||||
nbLots: parseInt(chatButton.attributes['data-quantiteNbLots']?.value),
|
||||
tailleLot: parseInt(chatButton.attributes['data-tailleLot']?.value ?? 1),
|
||||
prixLot: Number(chatButton.attributes['data-prixLot']?.value ?? 0),
|
||||
quantiteIllimite: chatButton.attributes['data-quantiteIllimite']?.value == 'true',
|
||||
chatMessageIdVente: RdDUtility.findChatMessageId(chatButton),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
static async onAcheter({ item, vendeur, acheteur, service, tailleLot, prixLot, nbLots, quantiteIllimite, chatMessageIdVente }) {
|
||||
const venteData = {
|
||||
item,
|
||||
actingUserId: game.user.id,
|
||||
vendeurId: vendeur?.id,
|
||||
vendeur,
|
||||
acheteur,
|
||||
service,
|
||||
tailleLot,
|
||||
quantiteIllimite,
|
||||
quantiteNbLots: nbLots,
|
||||
choix: { seForcer: false, supprimerSiZero: true },
|
||||
prixLot,
|
||||
isVente: prixLot > 0,
|
||||
isConsommable: item.type == 'nourritureboisson' && acheteur?.isPersonnage(),
|
||||
chatMessageIdVente
|
||||
};
|
||||
|
||||
DialogItemAchat.changeNombreLots(venteData, 1);
|
||||
let venteData = DialogItemAchat.prepareVenteData(buttonAcheter, vendeurId, vendeur, acheteur);
|
||||
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-achat.html`, venteData);
|
||||
new DialogItemAchat(html, venteData).render(true);
|
||||
const dialog = new DialogItemAchat(html, vendeur, acheteur, venteData, chatMessageIdVente);
|
||||
dialog.render(true);
|
||||
}
|
||||
|
||||
static changeNombreLots(venteData, nombreLots) {
|
||||
venteData.choix.nombreLots = nombreLots;
|
||||
venteData.prixTotal = (nombreLots * venteData.prixLot).toFixed(2);
|
||||
if (venteData.isConsommable) {
|
||||
const doses = nombreLots * venteData.tailleLot;
|
||||
venteData.totalSust = Misc.keepDecimals(doses * (venteData.item.system.sust ?? 0), 2);
|
||||
venteData.totalDesaltere = venteData.item.system.boisson
|
||||
? Misc.keepDecimals(doses * (venteData.item.system.desaltere ?? 0), 2)
|
||||
: 0;
|
||||
}
|
||||
}
|
||||
|
||||
constructor(html, venteData) {
|
||||
let options = { classes: ["dialogachat"], width: 400, height: 'fit-content', 'z-index': 99999 };
|
||||
constructor(html, vendeur, acheteur, venteData, chatMessageIdVente) {
|
||||
const isConsommable = venteData.item.type == 'nourritureboisson';
|
||||
let options = { classes: ["dialogachat"], width: 400, height: isConsommable ? 450 : 350, 'z-index': 99999 };
|
||||
|
||||
const actionAchat = venteData.prixLot > 0 ? "Acheter" : "Prendre";
|
||||
const buttons = {};
|
||||
if (venteData.isConsommable) {
|
||||
buttons["consommer"] = { label: venteData.item.system.boisson ? "Boire" : "Manger", callback: it => this.onAchatConsommer() }
|
||||
if (isConsommable) {
|
||||
buttons["consommer"] = { label: venteData.item.data.boisson ? "Boire" : "Manger", callback: it => { this.onAchatConsommer(); } }
|
||||
}
|
||||
buttons[actionAchat] = { label: actionAchat, callback: it => { this.onAchat(); } };
|
||||
buttons["decliner"] = { label: "Décliner", callback: it => { } };
|
||||
const acheteur = venteData.acheteur?.name ?? 'Un acheteur';
|
||||
const vendeur = (venteData.service ?? venteData.vendeur)?.name ?? 'Un vendeur';
|
||||
let conf = {
|
||||
title: `${acheteur} - ${actionAchat} à ${vendeur}`,
|
||||
title: venteData.acheteur? venteData.acheteur.name + " - " + actionAchat : actionAchat,
|
||||
content: html,
|
||||
default: actionAchat,
|
||||
buttons: buttons
|
||||
};
|
||||
|
||||
super(conf, options);
|
||||
|
||||
this.vendeur = vendeur;
|
||||
this.acheteur = acheteur;
|
||||
this.chatMessageIdVente = chatMessageIdVente;
|
||||
this.venteData = venteData;
|
||||
}
|
||||
|
||||
async onAchat() {
|
||||
await this.html.find(".nombreLots").change();
|
||||
(this.venteData.vendeur ?? this.venteData.acheteur).achatVente({
|
||||
userId: game.user.id,
|
||||
serviceId: this.venteData.service?.id,
|
||||
vendeurId: this.venteData.vendeur?.id,
|
||||
acheteurId: this.venteData.acheteur?.id,
|
||||
prixTotal: this.venteData.prixTotal,
|
||||
chatMessageIdVente: this.venteData.chatMessageIdVente,
|
||||
choix: this.venteData.choix,
|
||||
vente: this.venteData
|
||||
});
|
||||
static prepareVenteData(buttonAcheter, vendeurId, vendeur, acheteur) {
|
||||
const jsondata = buttonAcheter.attributes['data-jsondata']?.value;
|
||||
const prixLot = parseInt(buttonAcheter.attributes['data-prixLot']?.value ?? 0);
|
||||
let venteData = {
|
||||
item: JSON.parse(jsondata),
|
||||
vendeurId: vendeurId,
|
||||
vendeur: Misc.data(vendeur),
|
||||
acheteur: Misc.data(acheteur),
|
||||
tailleLot: parseInt(buttonAcheter.attributes['data-tailleLot']?.value ?? 1),
|
||||
quantiteIllimite: buttonAcheter.attributes['data-quantiteIllimite']?.value == 'true',
|
||||
quantiteNbLots: parseInt(buttonAcheter.attributes['data-quantiteNbLots']?.value),
|
||||
choix: {
|
||||
nombreLots: 1,
|
||||
seForcer: false,
|
||||
supprimerSiZero: true
|
||||
},
|
||||
prixLot: prixLot,
|
||||
prixTotal: prixLot,
|
||||
isVente: prixLot > 0
|
||||
};
|
||||
return venteData;
|
||||
}
|
||||
|
||||
async onAchat() {
|
||||
await $(".nombreLots").change();
|
||||
(this.vendeur ?? this.acheteur).achatVente({
|
||||
userId: game.user.id,
|
||||
vendeurId: this.vendeur?.id,
|
||||
acheteurId: this.acheteur?.id,
|
||||
prixTotal: this.venteData.prixTotal,
|
||||
chatMessageIdVente: this.chatMessageIdVente,
|
||||
choix: this.venteData.choix
|
||||
});
|
||||
}
|
||||
|
||||
async onAchatConsommer() {
|
||||
this.venteData.choix.consommer = true;
|
||||
await this.onAchat();
|
||||
@ -110,9 +96,9 @@ export class DialogItemAchat extends Dialog {
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
this.html = html;
|
||||
this.html.find(".nombreLots").change(event => this.setNombreLots(Number(event.currentTarget.value)));
|
||||
this.html.find(".se-forcer").change(event => this.setSeForcer(event));
|
||||
|
||||
html.find(".nombreLots").change(event => this.setNombreLots(Number(event.currentTarget.value)));
|
||||
html.find(".se-forcer").change(event => this.setSeForcer(event));
|
||||
}
|
||||
|
||||
setSeForcer(event) {
|
||||
@ -120,21 +106,9 @@ export class DialogItemAchat extends Dialog {
|
||||
}
|
||||
|
||||
setNombreLots(nombreLots) {
|
||||
|
||||
if (!this.venteData.quantiteIllimite) {
|
||||
if (!this.venteData.quantiteIllimite && nombreLots > this.venteData.quantiteNbLots) {
|
||||
ui.notifications.warn(`Seulement ${this.venteData.quantiteNbLots} lots disponibles, vous ne pouvez pas en prendre ${nombreLots}`)
|
||||
}
|
||||
nombreLots = Math.min(nombreLots, this.venteData.quantiteNbLots);
|
||||
}
|
||||
|
||||
DialogItemAchat.changeNombreLots(this.venteData, nombreLots);
|
||||
|
||||
this.html.find(".nombreLots").val(nombreLots);
|
||||
this.html.find(".prixTotal").text(this.venteData.prixTotal);
|
||||
this.html.find("span.total-sust").text(this.venteData.totalSust);
|
||||
this.html.find("span.total-desaltere").text(this.venteData.totalDesaltere);
|
||||
this.venteData.choix.nombreLots = nombreLots;
|
||||
this.venteData.prixTotal = (nombreLots * this.venteData.prixLot).toFixed(2);
|
||||
$(".prixTotal").text(this.venteData.prixTotal);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -2,14 +2,14 @@ import { Misc } from "./misc.js";
|
||||
|
||||
export class DialogConsommer extends Dialog {
|
||||
|
||||
static async create(actor, item, onActionItem = async () => { }) {
|
||||
static async create(actor, item, onActionItem = async ()=>{}) {
|
||||
const consommerData = DialogConsommer.prepareData(actor, item);
|
||||
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-item-consommer.html', consommerData);
|
||||
return new DialogConsommer(actor, item, consommerData, html, onActionItem)
|
||||
}
|
||||
|
||||
constructor(actor, item, consommerData, html, onActionItem = async () => { }) {
|
||||
const options = { classes: ["dialogconsommer"], width: 350, height: 'fit-content', 'z-index': 99999 };
|
||||
constructor(actor, item, consommerData, html, onActionItem = async ()=>{}) {
|
||||
const options = { classes: ["dialogconsommer"], width: 350, height: 450, 'z-index': 99999 };
|
||||
let conf = {
|
||||
title: consommerData.title,
|
||||
content: html,
|
||||
@ -17,9 +17,8 @@ export class DialogConsommer extends Dialog {
|
||||
buttons: {
|
||||
[consommerData.buttonName]: {
|
||||
label: consommerData.buttonName, callback: async it => {
|
||||
await this.onConsommer();
|
||||
await onActionItem();
|
||||
}
|
||||
await this.onConsommer(it);
|
||||
await onActionItem();}
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -31,71 +30,51 @@ export class DialogConsommer extends Dialog {
|
||||
this.consommerData = consommerData;
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
this.html = html;
|
||||
this.html.find(".se-forcer").change(event => this.setSeForcer(event));
|
||||
this.html.find(".consommer-doses").change(event => this.selectDoses(event));
|
||||
}
|
||||
|
||||
async onConsommer() {
|
||||
await this.html.find(".se-forcer").change();
|
||||
await this.html.find(".consommer-doses").change();
|
||||
async onConsommer(event) {
|
||||
await $(".se-forcer").change();
|
||||
await $(".consommer-doses").change();
|
||||
await this.actor.consommer(this.item, this.consommerData.choix);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static prepareData(actor, item) {
|
||||
const itemData = duplicate(Misc.data(item));
|
||||
let consommerData = {
|
||||
item: duplicate(item),
|
||||
cuisine: actor.getCompetence('cuisine'),
|
||||
item: itemData,
|
||||
cuisine: Misc.data(actor.getCompetence('cuisine')),
|
||||
choix: {
|
||||
doses: 1,
|
||||
seForcer: false,
|
||||
}
|
||||
}
|
||||
switch (item.type) {
|
||||
case 'herbe': case 'faune':
|
||||
consommerData.title = 'Manger une portion crue: ';
|
||||
consommerData.buttonName = "Manger";
|
||||
break;
|
||||
switch (itemData.type) {
|
||||
case 'nourritureboisson':
|
||||
consommerData.title = item.system.boisson ? 'Boire une dose: ' : 'Manger une portion: ';
|
||||
consommerData.buttonName = item.system.boisson ? "Boire" : "Manger";
|
||||
consommerData.title = itemData.data.boisson ? `${itemData.name}: boire une dose` : `${itemData.name}: manger une portion`;
|
||||
consommerData.buttonName = itemData.data.boisson ? "Boire" : "Manger";
|
||||
break;
|
||||
case 'potion':
|
||||
consommerData.title = 'Boire la potion: ';
|
||||
consommerData.title = `${itemData.name}: boire la potion`;
|
||||
consommerData.buttonName = "Boire";
|
||||
break;
|
||||
}
|
||||
consommerData.title += item.name;
|
||||
DialogConsommer.calculDoses(consommerData, item)
|
||||
DialogConsommer.calculDoses(consommerData, consommerData.choix.doses)
|
||||
return consommerData;
|
||||
}
|
||||
|
||||
static calculDoses(consommer, item) {
|
||||
const doses = consommer.choix.doses;
|
||||
switch (item.type) {
|
||||
case 'herbe': case 'faune':
|
||||
consommer.totalSust = doses;
|
||||
consommer.totalDesaltere = 0;
|
||||
consommer.choix.sust = 1;
|
||||
consommer.choix.quantite = 0;
|
||||
consommer.choix.encombrement = Misc.keepDecimals(consommer.item.system.encombrement / item.system.sust, 2);
|
||||
return;
|
||||
case 'nourritureboisson':
|
||||
consommer.choix.sust = consommer.item.system.sust;
|
||||
consommer.choix.quantite = doses;
|
||||
consommer.choix.encombrement = 0
|
||||
consommer.totalSust = Misc.keepDecimals(doses * (consommer.item.system.sust ?? 0), 2);
|
||||
consommer.totalDesaltere = consommer.item.system.boisson
|
||||
? Misc.keepDecimals(doses * (consommer.item.system.desaltere ?? 0), 2)
|
||||
: 0;
|
||||
break;
|
||||
case 'potion':
|
||||
consommer.totalSust = 0
|
||||
consommer.totalDesaltere = 0
|
||||
}
|
||||
static calculDoses(consommerData) {
|
||||
const doses = consommerData.choix.doses;
|
||||
consommerData.totalSust = Misc.keepDecimals(doses * (consommerData.item.data.sust ?? 0), 2);
|
||||
consommerData.totalDesaltere = consommerData.item.data.boisson
|
||||
? Misc.keepDecimals(doses * (consommerData.item.data.desaltere ?? 0), 2)
|
||||
: 0;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
html.find(".se-forcer").change(event => this.setSeForcer(event));
|
||||
html.find(".consommer-doses").change(event => this.selectDoses(event));
|
||||
}
|
||||
|
||||
|
||||
@ -105,8 +84,8 @@ export class DialogConsommer extends Dialog {
|
||||
|
||||
selectDoses(event) {
|
||||
this.consommerData.choix.doses = Number(event.currentTarget.value);
|
||||
DialogConsommer.calculDoses(this.consommerData, this.item);
|
||||
this.html.find(".total-sust").text(this.consommerData.totalSust);
|
||||
this.html.find(".total-desaltere").text(this.consommerData.totalDesaltere);
|
||||
DialogConsommer.calculDoses(this.consommerData);
|
||||
$(".total-sust").text(this.consommerData.totalSust);
|
||||
$(".total-desaltere").text(this.consommerData.totalDesaltere);
|
||||
}
|
||||
}
|
@ -1,32 +1,31 @@
|
||||
import { HtmlUtility } from "./html-utility.js";
|
||||
import { Misc } from "./misc.js";
|
||||
|
||||
export class DialogItemVente extends Dialog {
|
||||
|
||||
static async display({ item, callback, service = undefined, quantiteMax = undefined }) {
|
||||
const quantite = quantiteMax ?? item.getQuantite();
|
||||
const isOwned = item.isOwned;
|
||||
// const isOwned = item.isOwned || service?.actor;
|
||||
static async create(item, callback) {
|
||||
const itemData = Misc.data(item);
|
||||
const quantite = item.isConteneur() ? 1 : itemData.data.quantite;
|
||||
const venteData = {
|
||||
item: item,
|
||||
alias: item.actor?.name ?? service?.name ?? game.user.name,
|
||||
serviceId: service?.id,
|
||||
vendeurId: item.actor?.id ?? service?.actor?.id,
|
||||
prixOrigine: item.system.cout,
|
||||
prixUnitaire: item.system.cout,
|
||||
prixLot: item.system.cout,
|
||||
item: itemData,
|
||||
alias: item.actor?.name ?? game.user.name,
|
||||
vendeurId: item.actor?.id,
|
||||
prixOrigine: itemData.data.cout,
|
||||
prixUnitaire: itemData.data.cout,
|
||||
prixLot: itemData.data.cout,
|
||||
tailleLot: 1,
|
||||
quantiteNbLots: quantite,
|
||||
quantiteMaxLots: quantite,
|
||||
quantiteMax: quantite,
|
||||
quantiteIllimite: service? service.system.illimite : !isOwned,
|
||||
isOwned: isOwned,
|
||||
quantiteMax: quantite ,
|
||||
quantiteIllimite: !item.isOwned,
|
||||
isOwned: item.isOwned,
|
||||
};
|
||||
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-vente.html`, venteData);
|
||||
return new DialogItemVente(venteData, html, callback).render(true);
|
||||
return new DialogItemVente(venteData, html, callback);
|
||||
}
|
||||
|
||||
constructor(venteData, html, callback) {
|
||||
let options = { classes: ["dialogvente"], width: 400, height: 'fit-content', 'z-index': 99999 };
|
||||
let options = { classes: ["dialogvente"], width: 400, height: 300, 'z-index': 99999 };
|
||||
|
||||
let conf = {
|
||||
title: "Proposer",
|
||||
@ -40,26 +39,26 @@ export class DialogItemVente extends Dialog {
|
||||
this.venteData = venteData;
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
this.html = html;
|
||||
HtmlUtility._showControlWhen(this.html.find(".quantiteNbLots"), !this.venteData.quantiteIllimite)
|
||||
|
||||
this.html.find(".tailleLot").change(event => this.setTailleLot(Number(event.currentTarget.value)));
|
||||
this.html.find(".quantiteNbLots").change(event => this.setNbLots(Number(event.currentTarget.value)));
|
||||
this.html.find(".quantiteIllimite").change(event => this.setQuantiteIllimite(event.currentTarget.checked));
|
||||
this.html.find(".prixLot").change(event => this.setPrixLot(Number(event.currentTarget.value)));
|
||||
}
|
||||
|
||||
async onProposer(it) {
|
||||
await this.html.find(".tailleLot").change();
|
||||
await this.html.find(".quantiteNbLots").change();
|
||||
await this.html.find(".quantiteIllimite").change();
|
||||
await this.html.find(".prixLot").change();
|
||||
await $(".tailleLot").change();
|
||||
await $(".quantiteNbLots").change();
|
||||
await $(".quantiteIllimite").change();
|
||||
await $(".prixLot").change();
|
||||
this.callback(this.venteData);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
HtmlUtility._showControlWhen($(".quantiteNbLots"), !this.venteData.quantiteIllimite)
|
||||
|
||||
html.find(".tailleLot").change(event => this.setTailleLot(Number(event.currentTarget.value)));
|
||||
html.find(".quantiteNbLots").change(event => this.setNbLots(Number(event.currentTarget.value)));
|
||||
html.find(".quantiteIllimite").change(event => this.setQuantiteIllimite(event.currentTarget.checked));
|
||||
html.find(".prixLot").change(event => this.setPrixLot(Number(event.currentTarget.value)));
|
||||
}
|
||||
|
||||
setPrixLot(prixLot) {
|
||||
this.venteData.prixLot = prixLot;
|
||||
}
|
||||
@ -68,14 +67,16 @@ export class DialogItemVente extends Dialog {
|
||||
// recalculer le prix du lot
|
||||
if (tailleLot != this.venteData.tailleLot) {
|
||||
this.venteData.prixLot = (tailleLot * this.venteData.prixOrigine).toFixed(2);
|
||||
this.html.find(".prixLot").val(this.venteData.prixLot);
|
||||
$(".prixLot").val(this.venteData.prixLot);
|
||||
}
|
||||
this.venteData.tailleLot = tailleLot;
|
||||
// recalculer le nombre de lots max
|
||||
this.venteData.quantiteMaxLots = Math.floor(this.venteData.quantiteMax / tailleLot);
|
||||
this.venteData.quantiteNbLots = Math.min(this.venteData.quantiteMaxLots, this.venteData.quantiteNbLots);
|
||||
this.html.find(".quantiteNbLots").val(this.venteData.quantiteNbLots);
|
||||
this.html.find(".quantiteNbLots").attr("max", this.venteData.quantiteMaxLots)
|
||||
if (this.venteData.isOwned) {
|
||||
// recalculer le nombre de lots max
|
||||
this.venteData.quantiteMaxLots = Math.floor(this.venteData.quantiteMax / tailleLot);
|
||||
this.venteData.quantiteNbLots = Math.min(this.venteData.quantiteMaxLots, this.venteData.quantiteNbLots);
|
||||
$(".quantiteNbLots").val(this.venteData.quantiteNbLots);
|
||||
$(".quantiteNbLots").attr("max", this.venteData.quantiteMaxLots)
|
||||
}
|
||||
}
|
||||
|
||||
setNbLots(nbLots) {
|
||||
@ -83,12 +84,12 @@ export class DialogItemVente extends Dialog {
|
||||
nbLots = Math.max(0, Math.min(nbLots, this.venteData.quantiteMaxLots));
|
||||
}
|
||||
this.venteData.quantiteNbLots = nbLots;
|
||||
this.html.find(".quantiteNbLots").val(this.venteData.quantiteNbLots);
|
||||
$(".quantiteNbLots").val(this.venteData.quantiteNbLots);
|
||||
}
|
||||
|
||||
setQuantiteIllimite(checked) {
|
||||
this.venteData.quantiteIllimite = checked;
|
||||
this.html.find(".label-quantiteIllimite").text(this.venteData.quantiteIllimite ? "Illimités" : "disponibles");
|
||||
HtmlUtility._showControlWhen(this.html.find(".quantiteNbLots"), !this.venteData.quantiteIllimite)
|
||||
$(".label-quantiteIllimite").text(this.venteData.quantiteIllimite ? "Illimités" : "disponibles");
|
||||
HtmlUtility._showControlWhen($(".quantiteNbLots"), !this.venteData.quantiteIllimite)
|
||||
}
|
||||
}
|
@ -1,14 +1,15 @@
|
||||
import { Misc } from "./misc.js";
|
||||
|
||||
export class DialogRepos extends Dialog {
|
||||
|
||||
static async create(actor) {
|
||||
const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-repos.html", actor);
|
||||
const dialog = new DialogRepos(html, actor);
|
||||
dialog.render(true);
|
||||
let actorData = Misc.data(actor)
|
||||
const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-repos.html", actorData);
|
||||
new DialogRepos(html, actor).render(true);
|
||||
}
|
||||
|
||||
constructor(html, actor) {
|
||||
let options = { classes: ["DialogCreateSigneDraconiqueActorsActors"], width: 400, height: 'fit-content', 'z-index': 99999 };
|
||||
let options = { classes: ["DialogCreateSigneDraconiqueActorsActors"], width: 500, height: 400, 'z-index': 99999 };
|
||||
let conf = {
|
||||
title: "Se reposer",
|
||||
content: html,
|
||||
@ -20,18 +21,13 @@ export class DialogRepos extends Dialog {
|
||||
super(conf, options);
|
||||
this.actor = actor;
|
||||
}
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
this.html = html;
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
|
||||
async repos() {
|
||||
await this.html.find("[name='nb-heures']").change();
|
||||
await this.html.find("[name='nb-jours']").change();
|
||||
const selection = await this.html.find("[name='repos']:checked").val();
|
||||
const nbHeures = Number.parseInt(await this.html.find("[name='nb-heures']").val());
|
||||
const nbJours = Number.parseInt(await this.html.find("[name='nb-jours']").val());
|
||||
await $("[name='nb-heures']").change();
|
||||
await $("[name='nb-jours']").change();
|
||||
const selection = await $("[name='repos']:checked").val();
|
||||
const nbHeures = Number.parseInt(await $("[name='nb-heures']").val());
|
||||
const nbJours = Number.parseInt(await $("[name='nb-jours']").val());
|
||||
switch (selection) {
|
||||
case "sieste": {
|
||||
await this.actor.dormir(nbHeures);
|
||||
@ -39,7 +35,7 @@ export class DialogRepos extends Dialog {
|
||||
}
|
||||
case "nuit": {
|
||||
let heuresDormies = await this.actor.dormir(nbHeures);
|
||||
if (heuresDormies == nbHeures) {
|
||||
if (heuresDormies == nbHeures){
|
||||
await this.actor.dormirChateauDormant();
|
||||
}
|
||||
return;
|
||||
@ -53,4 +49,8 @@ export class DialogRepos extends Dialog {
|
||||
}
|
||||
}
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
|
||||
export class DialogSelectTarget extends Dialog {
|
||||
constructor(html, onSelectTarget, targets) {
|
||||
const options = {
|
||||
classes: ["rdd-dialog-select-target"],
|
||||
width: 'fit-content',
|
||||
height: 'fit-content',
|
||||
'max-height': 600,
|
||||
'z-index': 99999
|
||||
};
|
||||
const conf = {
|
||||
title: "Choisir une cible",
|
||||
content: html,
|
||||
buttons: {}
|
||||
};
|
||||
super(conf, options);
|
||||
this.onSelectTarget = onSelectTarget;
|
||||
this.targets = targets;
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
this.html = html;
|
||||
this.html.find("li.select-target").click((event) => {
|
||||
this.targetSelected(this.html.find(event.currentTarget)?.data("token-id"));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
targetSelected(tokenId) {
|
||||
const target = this.targets.find(it => it.id == tokenId);
|
||||
this.close();
|
||||
if (target) {
|
||||
this.onSelectTarget(target);
|
||||
}
|
||||
}
|
||||
}
|
@ -3,43 +3,50 @@ import { Misc } from "./misc.js";
|
||||
export class DialogSplitItem extends Dialog {
|
||||
|
||||
static async create(item, callback) {
|
||||
const itemData = Misc.data(item);
|
||||
const splitData = {
|
||||
item: item,
|
||||
choix: { quantite: 1, max: item.system.quantite - 1 }
|
||||
item: itemData,
|
||||
choix: { quantite: 1, max: itemData.data.quantite - 1 }
|
||||
};
|
||||
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-split.html`, splitData);
|
||||
return new DialogSplitItem(item, splitData, html, callback)
|
||||
}
|
||||
|
||||
constructor(item, splitData, html, callback) {
|
||||
let options = { classes: ["dialogsplit"], width: 300, height: 'fit-content', 'z-index': 99999 };
|
||||
let options = { classes: ["dialogsplit"], width: 300, height: 160, 'z-index': 99999 };
|
||||
|
||||
let conf = {
|
||||
title: "Séparer en deux",
|
||||
content: html,
|
||||
default: "separer",
|
||||
buttons: {
|
||||
"separer": { label: "Séparer", callback: it => this.onSplit() }
|
||||
"separer": {
|
||||
label: "Séparer", callback: it => {
|
||||
this.onSplit();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
super(conf, options);
|
||||
|
||||
|
||||
this.callback = callback;
|
||||
this.item = item;
|
||||
this.splitData = splitData;
|
||||
}
|
||||
|
||||
async onSplit(){
|
||||
await $(".choix-quantite").change();
|
||||
this.callback(this.item, this.splitData.choix.quantite);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
this.html = html;
|
||||
this.html.find(".choix-quantite").change(event => {
|
||||
|
||||
html.find(".choix-quantite").change(event => {
|
||||
this.splitData.choix.quantite = Number(event.currentTarget.value);
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async onSplit() {
|
||||
await this.html.find(".choix-quantite").change();
|
||||
this.callback(this.item, this.splitData.choix.quantite);
|
||||
}
|
||||
|
||||
}
|
@ -1,18 +1,18 @@
|
||||
import { Misc } from "./misc.js";
|
||||
|
||||
export class DialogStress extends Dialog {
|
||||
|
||||
static async distribuerStress() {
|
||||
const dialogData = {
|
||||
let dialogData = {
|
||||
motif: "Motif",
|
||||
stress: 10,
|
||||
immediat: false,
|
||||
actors: game.actors.filter(actor => actor.hasPlayerOwner && actor.isPersonnage())
|
||||
.map(actor => ({
|
||||
id: actor.id,
|
||||
name: actor.name,
|
||||
selected: true
|
||||
})
|
||||
)
|
||||
.map(actor => {
|
||||
let actorData = duplicate(Misc.data(actor));
|
||||
actorData.selected = actor.hasPlayerOwner;
|
||||
return actorData;
|
||||
})
|
||||
};
|
||||
|
||||
const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-stress.html", dialogData);
|
||||
@ -21,43 +21,52 @@ export class DialogStress extends Dialog {
|
||||
}
|
||||
|
||||
constructor(dialogData, html) {
|
||||
const options = { classes: ["DialogStress"],
|
||||
width: 400,
|
||||
height: 'fit-content',
|
||||
'z-index': 99999
|
||||
};
|
||||
const conf = {
|
||||
let options = { classes: ["DialogStress"], width: 400, height: 320, 'z-index': 99999 };
|
||||
let conf = {
|
||||
title: "Donner du stress",
|
||||
content: html,
|
||||
buttons: {
|
||||
stress: { label: "Stress !", callback: it => { this.onStress(); } }
|
||||
"Stress": { label: "Stress !", callback: it => { this._onStress(); } }
|
||||
}
|
||||
};
|
||||
super(conf, options);
|
||||
this.dialogData = dialogData;
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
this.html = html;
|
||||
this.html.find("input.select-actor").change((event) => this.onSelectActor(event));
|
||||
}
|
||||
|
||||
async onStress() {
|
||||
const motif = this.html.find("form.rdddialogstress input[name='motif']").val();
|
||||
const stress = Number(this.html.find("form.rdddialogstress input[name='stress']").val());
|
||||
const compteur = (this.html.find("form.rdddialogstress input[name='immediat']").prop("checked")) ? 'experience' : 'stress';
|
||||
async _onStress() {
|
||||
this.validerStress();
|
||||
const compteur = this.dialogData.immediat ? 'experience' : 'stress';
|
||||
const stress = this.dialogData.stress;
|
||||
const motif = this.dialogData.motif;
|
||||
|
||||
this.dialogData.actors.filter(it => it.selected)
|
||||
.map(it => game.actors.get(it.id))
|
||||
.map(it => game.actors.get(it._id))
|
||||
.forEach(actor => actor.distribuerStress(compteur, stress, motif));
|
||||
}
|
||||
|
||||
async onSelectActor(event) {
|
||||
const actorId = this.html.find(event.currentTarget)?.data("actor-id");
|
||||
const actor = this.dialogData.actors.find(it => it.id == actorId);
|
||||
if (actor) {
|
||||
actor.selected = event.currentTarget.checked;
|
||||
}
|
||||
|
||||
validerStress() {
|
||||
this.dialogData.motif = $("form.rdddialogstress input[name='motif']").val();
|
||||
this.dialogData.stress = $("form.rdddialogstress input[name='stress']").val();
|
||||
this.dialogData.immediat = $("form.rdddialogstress input[name='immediat']").prop("checked");;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
html.find(".select-actor").change((event) => this.onSelectActor(event));
|
||||
}
|
||||
|
||||
async onSelectActor(event) {
|
||||
event.preventDefault();
|
||||
const options = event.currentTarget.options;
|
||||
for (var i = 0; i < options.length; i++) { // looping over the options
|
||||
const actorId = options[i].attributes["data-actor-id"].value;
|
||||
const actor = this.dialogData.actors.find(it => it._id == actorId);
|
||||
if (actor) {
|
||||
actor.selected = options[i].selected;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
import { HIDE_DICE, SHOW_DICE } from "./constants.js";
|
||||
import { RdDUtility } from "./rdd-utility.js";
|
||||
|
||||
/**
|
||||
* Extend the base Dialog entity by defining a custom window to perform roll.
|
||||
* @extends {Dialog}
|
||||
*/
|
||||
export class DialogValidationEncaissement extends Dialog {
|
||||
|
||||
static async validerEncaissement(actor, rollData, armure, show, onEncaisser) {
|
||||
let encaissement = await RdDUtility.jetEncaissement(rollData, armure, { showDice: HIDE_DICE });
|
||||
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-validation-encaissement.html', {
|
||||
actor: actor,
|
||||
rollData: rollData,
|
||||
encaissement: encaissement,
|
||||
show: show
|
||||
});
|
||||
const dialog = new DialogValidationEncaissement(html, actor, rollData, armure, encaissement, show, onEncaisser);
|
||||
dialog.render(true);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(html, actor, rollData, armure, encaissement, show, onEncaisser) {
|
||||
// Common conf
|
||||
let buttons = {
|
||||
"valider": { label: "Valider", callback: html => this.validerEncaissement() },
|
||||
"annuler": { label: "Annuler", callback: html => { } },
|
||||
};
|
||||
|
||||
let dialogConf = {
|
||||
title: "Validation d'encaissement",
|
||||
content: html,
|
||||
buttons: buttons,
|
||||
default: "valider"
|
||||
}
|
||||
|
||||
let dialogOptions = {
|
||||
classes: ["rdd-roll-dialog"],
|
||||
width: 350,
|
||||
height: 290
|
||||
}
|
||||
|
||||
// Select proper roll dialog template and stuff
|
||||
super(dialogConf, dialogOptions);
|
||||
|
||||
this.actor = actor
|
||||
this.rollData = rollData;
|
||||
this.armure = armure;
|
||||
this.encaissement = encaissement;
|
||||
this.show = show;
|
||||
this.onEncaisser = onEncaisser;
|
||||
this.forceDiceResult = {total: encaissement.roll.result };
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
this.html = html;
|
||||
this.html.find('input.encaissement-roll-result').keyup(async event => {
|
||||
this.forceDiceResult.total = event.currentTarget.value;
|
||||
this.encaissement = await RdDUtility.jetEncaissement(this.rollData, this.armure, { showDice: HIDE_DICE, forceDiceResult: this.forceDiceResult});
|
||||
this.html.find('label.encaissement-total').text(this.encaissement.total);
|
||||
this.html.find('label.encaissement-blessure').text(this.encaissement.blessures)
|
||||
});
|
||||
}
|
||||
|
||||
async validerEncaissement() {
|
||||
this.encaissement = await RdDUtility.jetEncaissement(this.rollData, this.armure, { showDice: SHOW_DICE, forceDiceResult: this.forceDiceResult});
|
||||
this.onEncaisser(this.encaissement, this.show)
|
||||
}
|
||||
}
|
@ -1,137 +0,0 @@
|
||||
import { ChatUtility } from "./chat-utility.js";
|
||||
import { Poetique } from "./poetique.js";
|
||||
import { RdDDice } from "./rdd-dice.js";
|
||||
import { TMRUtility } from "./tmr-utility.js";
|
||||
|
||||
export class EffetsRencontre {
|
||||
|
||||
static messager = async (dialog, context) => {
|
||||
dialog.setRencontreState('messager', TMRUtility.getTMRPortee(context.tmr.coord, context.rencontre.system.force));
|
||||
}
|
||||
|
||||
static passeur = async (dialog, context) => {
|
||||
dialog.setRencontreState('passeur', TMRUtility.getTMRPortee(context.tmr.coord, context.rencontre.system.force));
|
||||
}
|
||||
|
||||
static teleportation_typecase = async (dialog, context) => {
|
||||
dialog.setRencontreState('changeur', TMRUtility.getCasesType(context.tmr.type));
|
||||
}
|
||||
|
||||
static rencontre_persistante = async (dialog, context) => {
|
||||
dialog.setRencontreState('persistant', []);
|
||||
}
|
||||
|
||||
static reve_plus_force = async (dialog, context) => { await EffetsRencontre.$reve_plus(context.actor, context.rencontre.system.force) }
|
||||
static reve_plus_1 = async (dialog, context) => { await EffetsRencontre.$reve_plus(context.actor, 1) }
|
||||
static reve_moins_force = async (dialog, context) => { await EffetsRencontre.$reve_plus(context.actor, -context.rencontre.system.force) }
|
||||
static reve_moins_1 = async (dialog, context) => { await EffetsRencontre.$reve_plus(context.actor, -1) }
|
||||
static $reve_plus = async (actor, valeur) => { await actor.reveActuelIncDec(valeur) }
|
||||
|
||||
static vie_moins_1 = async (dialog, context) => { await EffetsRencontre.$vie_plus(context.actor, -1) }
|
||||
static vie_moins_force = async (dialog, context) => { await EffetsRencontre.$vie_plus(context.actor, -context.rencontre.system.force) }
|
||||
static $vie_plus = async (actor, valeur) => { await actor.santeIncDec("vie", valeur) }
|
||||
|
||||
static moral_plus_1 = async (dialog, context) => { await EffetsRencontre.$vie_plus(context.actor, 1) }
|
||||
static moral_moins_1 = async (dialog, context) => { await EffetsRencontre.$vie_plus(context.actor, -1) }
|
||||
static $moral_plus = async (actor, valeur) => { await actor.moralIncDec(valeur) }
|
||||
|
||||
static end_moins_1 = async (dialog, context) => { await EffetsRencontre.$vie_plus(context.actor, -1) }
|
||||
static end_moins_force = async (dialog, context) => { await EffetsRencontre.$vie_plus(context.actor, -context.rencontre.system.force) }
|
||||
static $end_plus = async (actor, valeur) => { await actor.santeIncDec("endurance", valeur) }
|
||||
|
||||
static fatigue_plus_1 = async (dialog, context) => { await EffetsRencontre.$fatigue_plus(context.actor, 1) }
|
||||
static fatigue_plus_force = async (dialog, context) => { await EffetsRencontre.$fatigue_plus(context.actor, context.rencontre.system.force) }
|
||||
static fatigue_moins_1 = async (dialog, context) => { await EffetsRencontre.$fatigue_plus(context.actor, -1) }
|
||||
static fatigue_moins_force = async (dialog, context) => { await EffetsRencontre.$fatigue_plus(context.actor, -context.rencontre.system.force) }
|
||||
static $fatigue_plus = async (actor, valeur) => { await actor.santeIncDec("fatigue", valeur) }
|
||||
|
||||
static perte_chance = async (dialog, context) => {
|
||||
const perte = context.rolled.isETotal ? context.rencontre.system.force : 1;
|
||||
await context.actor.chanceActuelleIncDec("fatigue", -perte);
|
||||
}
|
||||
|
||||
static xp_sort_force = async (dialog, context) => {
|
||||
let competence = context.competence;
|
||||
if (competence) {
|
||||
const xpSort = Misc.toInt(competence.system.xp_sort) + context.rencontre.system.force;
|
||||
await this.updateEmbeddedDocuments("Item", [{ _id: compData._id, 'system.xp_sort': xpSort }]);
|
||||
await this.updateExperienceLog("XP Sort", xpSort, `Rencontre d'un ${context.rencontre.name} en TMR`);
|
||||
}
|
||||
}
|
||||
|
||||
static stress_plus_1 = async (dialog, context) => {
|
||||
await context.actor.addCompteurValue('stress', 1, `Rencontre d'un ${context.rencontre.name} en TMR`);
|
||||
}
|
||||
|
||||
static reinsertion = async (dialog, context) => {
|
||||
await EffetsRencontre.$reinsertion(dialog, context.actor, it => true)
|
||||
}
|
||||
|
||||
static teleportation_aleatoire_typecase = async (dialog, context) => {
|
||||
await EffetsRencontre.$reinsertion(dialog, context.actor, it => it.type == context.tmr.type && it.coord != context.tmr.coord)
|
||||
}
|
||||
|
||||
static demireve_rompu = async (dialog, context) => {
|
||||
dialog.close()
|
||||
}
|
||||
|
||||
static sort_aleatoire = async (dialog, context) => {
|
||||
context.sortReserve = await RdDDice.rollOneOf(context.actor.itemTypes['sortreserve']);
|
||||
if (context.sortReserve) {
|
||||
context.newTMR = TMRUtility.getTMR(context.sortReserve.system.coord);
|
||||
await dialog.positionnerDemiReve(context.newTMR.coord);
|
||||
await dialog.processSortReserve(context.sortReserve);
|
||||
dialog.close();
|
||||
}
|
||||
else {
|
||||
await EffetsRencontre.$reinsertion(dialog, context.actor, it => true);
|
||||
}
|
||||
}
|
||||
|
||||
static deplacement_aleatoire = async (dialog, context) => {
|
||||
const oldCoord = context.actor.system.reve.tmrpos.coord;
|
||||
const newTmr = await TMRUtility.deplaceTMRAleatoire(context.actor, oldCoord);
|
||||
await dialog.positionnerDemiReve(newTmr.coord)
|
||||
}
|
||||
|
||||
static rdd_part_tete = async (dialog, context) => {
|
||||
mergeObject(context, {
|
||||
tete: context.rolled.isPart,
|
||||
poesie: await Poetique.getExtrait()
|
||||
})
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(context.actor.name),
|
||||
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-reve-de-dragon.html`, context)
|
||||
});
|
||||
}
|
||||
|
||||
static rdd_echec_queue = async (dialog, context) => {
|
||||
mergeObject(context, {
|
||||
queues: [await context.actor.ajouterQueue()],
|
||||
poesie: await Poetique.getExtrait()
|
||||
})
|
||||
if (context.rolled.isETotal) {
|
||||
context.queues.push(await context.actor.ajouterQueue());
|
||||
}
|
||||
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-reve-de-dragon.html`, context)
|
||||
});
|
||||
}
|
||||
|
||||
static experience_particuliere = async (dialog, context) => {
|
||||
await context.actor.appliquerAjoutExperience(context)
|
||||
}
|
||||
|
||||
static regain_seuil = async (dialog, context) => {
|
||||
await context.actor.regainPointDeSeuil()
|
||||
}
|
||||
|
||||
static async $reinsertion(dialog, actor, filter) {
|
||||
const newTMR = await TMRUtility.getTMRAleatoire(filter);
|
||||
await actor.forcerPositionTMRInconnue(newTMR);
|
||||
await dialog.positionnerDemiReve(newTMR.coord);
|
||||
}
|
||||
|
||||
}
|
@ -1,223 +0,0 @@
|
||||
import { SYSTEM_RDD } from "./constants.js";
|
||||
import { Grammar } from "./grammar.js";
|
||||
import { Misc } from "./misc.js";
|
||||
import { CompendiumTableHelpers, CompendiumTable } from "./settings/system-compendiums.js";
|
||||
|
||||
const RARETES = [
|
||||
{ name: 'Commune', frequence: 54, min: 27, max: 108 },
|
||||
{ name: 'Frequente', frequence: 18, min: 9, max: 36 },
|
||||
{ name: 'Rare', frequence: 6, min: 3, max: 12 },
|
||||
{ name: 'Rarissime', frequence: 2, min: 1, max: 4 }]
|
||||
const DEFAULT_RARETE = 1;
|
||||
|
||||
const SETTINGS_LISTE_MILIEUX = "liste-milieux";
|
||||
const MILIEUX = [
|
||||
"Collines",
|
||||
"Cours d'eau",
|
||||
"Déserts",
|
||||
"Forêts",
|
||||
"Marais",
|
||||
"Maritimes",
|
||||
"Montagnes",
|
||||
"Plaines",
|
||||
"Sous-sols"
|
||||
]
|
||||
const ITEM_ENVIRONNEMENT_TYPES = [
|
||||
'herbe', 'ingredient', 'faune'
|
||||
]
|
||||
|
||||
export class Environnement {
|
||||
|
||||
static init() {
|
||||
game.settings.register(SYSTEM_RDD, SETTINGS_LISTE_MILIEUX, {
|
||||
name: "Liste des milieux proposés",
|
||||
hint: "Liste des milieux proposés pour la faune&flore, séparés par des virgules",
|
||||
scope: "world",
|
||||
config: true,
|
||||
default: MILIEUX.reduce(Misc.joining(',')),
|
||||
type: String
|
||||
});
|
||||
game.system.rdd.environnement = new Environnement();
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.table = new CompendiumTable('faune-flore-mineraux', 'Item', ITEM_ENVIRONNEMENT_TYPES)
|
||||
}
|
||||
|
||||
static getRarete(name = undefined) {
|
||||
return RARETES.find(it => it.name == name) ?? RARETES[DEFAULT_RARETE];
|
||||
}
|
||||
|
||||
static getFrequenceRarete(rarete, field = undefined) {
|
||||
const selected = this.getRarete(rarete);
|
||||
return selected[field];
|
||||
}
|
||||
|
||||
async milieux() {
|
||||
return Object.values(await this.mapMilieux());
|
||||
}
|
||||
|
||||
async mapMilieux() {
|
||||
const compendiumItems = await this.getElements(it => 1, it => ITEM_ENVIRONNEMENT_TYPES.includes(it.type));
|
||||
return Misc.indexLowercase(this.getMilieuxSettings().concat(Environnement.listMilieux(compendiumItems)));
|
||||
}
|
||||
|
||||
static listMilieux(items) {
|
||||
return Misc.concat(items.map(it => Environnement.$itemToMilieux(it).filter(m => m)));
|
||||
}
|
||||
|
||||
async autresMilieux(item) {
|
||||
const mapMilieux = await this.mapMilieux();
|
||||
const milieuxExistants = Environnement.$itemToMilieux(item).map(it => Grammar.toLowerCaseNoAccent(it));
|
||||
return Object.keys(mapMilieux)
|
||||
.filter(it => !milieuxExistants.includes(it))
|
||||
.map(it => mapMilieux[it]);
|
||||
}
|
||||
|
||||
static $itemToMilieux(item) {
|
||||
return item.system.environnement.map(env => env.milieu);
|
||||
}
|
||||
|
||||
getMilieuxSettings() {
|
||||
return game.settings.get(SYSTEM_RDD, SETTINGS_LISTE_MILIEUX).split(',').map(it => it.trim()).filter(it => it != '');
|
||||
}
|
||||
|
||||
async findEnvironnementsLike(search) {
|
||||
const milieux = await this.mapMilieux();
|
||||
const searchLower = Grammar.toLowerCaseNoAccent(search);
|
||||
const keys = Object.keys(milieux).filter(it => it.includes(searchLower));
|
||||
if (keys.length > 1) {
|
||||
const milieuExact = milieux[searchLower];
|
||||
if (milieuExact) {
|
||||
return [milieuExact];
|
||||
}
|
||||
}
|
||||
return keys.map(k => milieux[k]);
|
||||
}
|
||||
|
||||
async searchToChatMessage(milieux, typeName) {
|
||||
const table = await this.buildEnvironnementTable(milieux);
|
||||
await CompendiumTableHelpers.tableToChatMessage(table, 'Item', ITEM_ENVIRONNEMENT_TYPES, typeName);
|
||||
return true
|
||||
}
|
||||
|
||||
async getRandom(milieux, typeName) {
|
||||
const table = await this.buildEnvironnementTable(milieux);
|
||||
return await CompendiumTableHelpers.getRandom(table, 'Item', ITEM_ENVIRONNEMENT_TYPES, undefined, typeName);
|
||||
}
|
||||
|
||||
async buildEnvironnementTable(milieux) {
|
||||
const filterMilieux = item => item.system?.environnement.filter(env => milieux.includes(env.milieu));
|
||||
const itemRareteEnMilieu = item => {
|
||||
const raretes = filterMilieux(item);
|
||||
const frequenceMax = Math.max(raretes.map(env => env.frequence));
|
||||
return raretes.find(env => env.frequence == frequenceMax);
|
||||
}
|
||||
const itemFrequenceEnMilieu = item => itemRareteEnMilieu(item)?.frequence ?? 0;
|
||||
const isPresentEnMilieu = item => itemFrequenceEnMilieu(item) > 0;
|
||||
return await this.table.buildTable(itemFrequenceEnMilieu, isPresentEnMilieu);
|
||||
}
|
||||
|
||||
|
||||
async getElements(itemFrequence, filter) {
|
||||
return await this.table.getContent(itemFrequence, filter);
|
||||
}
|
||||
}
|
||||
|
||||
export class EnvironmentSheetHelper {
|
||||
|
||||
static defaultOptions(defaultOptions) {
|
||||
return mergeObject(defaultOptions, {
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "informations" }]
|
||||
});
|
||||
}
|
||||
|
||||
static setPosition(sheet, superPosition) {
|
||||
const position = superPosition;
|
||||
const sheetHeader = sheet.element.find(".sheet-header");
|
||||
const sheetBody = sheet.element.find(".sheet-body");
|
||||
sheetBody.css("height", position.height - sheetHeader[0].clientHeight)
|
||||
return position;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async getData(sheet, formData) {
|
||||
return mergeObject(formData, {
|
||||
milieux: await game.system.rdd.environnement.autresMilieux(sheet.item)
|
||||
});
|
||||
}
|
||||
|
||||
static activateListeners(sheet) {
|
||||
if (!sheet.options.editable) return;
|
||||
|
||||
sheet.html.find("input.input-selection-milieu").keypress(event => {
|
||||
if (event.keyCode == '13') {
|
||||
EnvironmentSheetHelper.onAddMilieu(sheet, event);
|
||||
}
|
||||
event.stopPropagation();
|
||||
})
|
||||
sheet.html.find("a.milieu-add").click(event => EnvironmentSheetHelper.onAddMilieu(sheet, event));
|
||||
sheet.html.find("div.environnement-milieu a.milieu-delete").click(event => EnvironmentSheetHelper.onDeleteMilieu(sheet, event));
|
||||
sheet.html.find("div.environnement-milieu select.environnement-rarete").change(event => EnvironmentSheetHelper.onChange(sheet, event,
|
||||
updated => EnvironmentSheetHelper.$changeRarete(sheet, event, updated)));
|
||||
sheet.html.find("div.environnement-milieu input[name='environnement-frequence']").change(event => EnvironmentSheetHelper.onChange(sheet, event,
|
||||
updated => EnvironmentSheetHelper.$changeFrequence(sheet, event, updated)));
|
||||
}
|
||||
|
||||
static $changeFrequence(sheet, event, updated) {
|
||||
updated.frequence = Number(sheet.html.find(event.currentTarget).val());
|
||||
}
|
||||
|
||||
static $changeRarete(sheet, event, updated) {
|
||||
const name = sheet.html.find(event.currentTarget).val();
|
||||
const rarete = Environnement.getRarete(name);
|
||||
updated.rarete = rarete.name;
|
||||
updated.frequence = rarete.frequence;
|
||||
// updated.frequence = Math.min(
|
||||
// Math.max(rarete.min, updated.frequence ?? rarete.frequence),
|
||||
// rarete.max);
|
||||
}
|
||||
|
||||
static async onAddMilieu(sheet, event) {
|
||||
const milieu = sheet.html.find('input.input-selection-milieu').val();
|
||||
if (!milieu) {
|
||||
ui.notifications.warn(`Choisissez le milieu dans lequel se trouve le/la ${sheet.item.name}`);
|
||||
return
|
||||
}
|
||||
const list = sheet.item.system.environnement;
|
||||
const exists = list.find(it => it.milieu == milieu);
|
||||
if (exists) {
|
||||
ui.notifications.warn(`${sheet.item.name} a déjà une rareté ${exists.rarete} en ${milieu} (fréquence: ${exists.frequence})`);
|
||||
return
|
||||
}
|
||||
const rarete = Environnement.getRarete();
|
||||
const newList = [...list, { milieu, rarete: rarete.name, frequence: rarete.frequence }].sort(Misc.ascending(it => it.milieu))
|
||||
await sheet.item.update({ 'system.environnement': newList })
|
||||
}
|
||||
|
||||
static async onDeleteMilieu(sheet, event) {
|
||||
const milieu = EnvironmentSheetHelper.$getEventMilieu(sheet, event);
|
||||
if (milieu != undefined) {
|
||||
const newList = sheet.item.system.environnement.filter(it => it.milieu != milieu)
|
||||
.sort(Misc.ascending(it => it.milieu));
|
||||
await sheet.item.update({ 'system.environnement': newList });
|
||||
}
|
||||
}
|
||||
|
||||
static async onChange(sheet, event, doMutation) {
|
||||
const list = sheet.item.system.environnement;
|
||||
const milieu = EnvironmentSheetHelper.$getEventMilieu(sheet, event);
|
||||
const updated = list.find(it => it.milieu == milieu);
|
||||
if (updated) {
|
||||
doMutation(updated);
|
||||
const newList = [...list.filter(it => it.milieu != milieu), updated]
|
||||
.sort(Misc.ascending(it => it.milieu));
|
||||
await sheet.item.update({ 'system.environnement': newList });
|
||||
}
|
||||
}
|
||||
|
||||
static $getEventMilieu(sheet, event) {
|
||||
return sheet.html.find(event.currentTarget)?.parents("div.environnement-milieu").data("milieu");
|
||||
}
|
||||
|
||||
}
|
@ -19,14 +19,10 @@ export class Grammar {
|
||||
return word.match(/^[aeiouy]/i)
|
||||
}
|
||||
|
||||
static equalsInsensitive(a, b) {
|
||||
return Grammar.toLowerCaseNoAccent(a) == Grammar.toLowerCaseNoAccent(b)
|
||||
}
|
||||
|
||||
static includesLowerCaseNoAccent(value, content) {
|
||||
return Grammar.toLowerCaseNoAccent(value).includes(Grammar.toLowerCaseNoAccent(content));
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static toLowerCaseNoAccent(words) {
|
||||
return words?.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "") ?? words;
|
||||
|
9
module/hook-renderChatLog.js
Normal file
@ -0,0 +1,9 @@
|
||||
/* -------------------------------------------- */
|
||||
import { RdDUtility } from "./rdd-utility.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
// Activate chat listeners defined
|
||||
// Hooks.on('renderChatLog', (log, html, data) => {
|
||||
// RdDUtility.chatListeners(html);
|
||||
// });
|
||||
|
@ -1,10 +1,10 @@
|
||||
export class HtmlUtility{
|
||||
static _showControlWhen(jQuerySelector, condition) {
|
||||
static _showControlWhen(control, condition) {
|
||||
if (condition) {
|
||||
jQuerySelector.show();
|
||||
control.show();
|
||||
}
|
||||
else {
|
||||
jQuerySelector.hide();
|
||||
control.hide();
|
||||
}
|
||||
}
|
||||
}
|
@ -19,34 +19,36 @@ const nomCategorieParade = {
|
||||
/* -------------------------------------------- */
|
||||
export class RdDItemArme extends Item {
|
||||
|
||||
static isArme(item) {
|
||||
return (item.type == 'competencecreature' && item.system.iscombat) || item.type == 'arme';
|
||||
static isArme(itemData) {
|
||||
itemData = Misc.data(itemData);
|
||||
return (itemData.type == 'competencecreature' && itemData.data.iscombat) || itemData.type == 'arme';
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getArme(arme) {
|
||||
switch (arme ? arme.type : '') {
|
||||
case 'arme': return arme;
|
||||
static getArmeData(armeData) {
|
||||
armeData = Misc.data(armeData);
|
||||
switch (armeData ? armeData.type : '') {
|
||||
case 'arme': return armeData;
|
||||
case 'competencecreature':
|
||||
return RdDItemCompetenceCreature.armeNaturelle(arme);
|
||||
return RdDItemCompetenceCreature.toActionArme(armeData);
|
||||
}
|
||||
return RdDItemArme.mainsNues();
|
||||
}
|
||||
|
||||
static computeNiveauArmes(armes, competences) {
|
||||
for (const arme of armes) {
|
||||
arme.system.niveau = RdDItemArme.niveauCompetenceArme(arme, competences);
|
||||
arme.data.niveau = RdDItemArme.niveauCompetenceArme(arme, competences);
|
||||
}
|
||||
}
|
||||
|
||||
static niveauCompetenceArme(arme, competences) {
|
||||
const compArme = competences.find(it => it.name == arme.system.competence);
|
||||
return compArme?.system.niveau ?? -8;
|
||||
const compArme = competences.find(it => it.name == arme.data.competence);
|
||||
return compArme?.data.niveau ?? -8;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getNomCategorieParade(arme) {
|
||||
const categorie = arme?.system ? RdDItemArme.getCategorieParade(arme) : arme;
|
||||
const categorie = arme?.data ? RdDItemArme.getCategorieParade(arme) : arme;
|
||||
return nomCategorieParade[categorie];
|
||||
}
|
||||
|
||||
@ -64,20 +66,21 @@ export class RdDItemArme extends Item {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getCategorieParade(armeData) {
|
||||
if (armeData.system.categorie_parade) {
|
||||
return armeData.system.categorie_parade;
|
||||
armeData = Misc.data(armeData);
|
||||
if (armeData.data.categorie_parade) {
|
||||
return armeData.data.categorie_parade;
|
||||
}
|
||||
// pour compatibilité avec des personnages existants
|
||||
if (armeData.type == 'competencecreature' || armeData.system.categorie == 'creature') {
|
||||
return armeData.system.categorie_parade || (armeData.system.isparade ? 'armes-naturelles' : '');
|
||||
if (armeData.type == 'competencecreature' || armeData.data.categorie == 'creature') {
|
||||
return armeData.data.categorie_parade || (armeData.data.isparade ? 'armes-naturelles' : '');
|
||||
}
|
||||
if (!armeData.type.match(/arme|competencecreature/)) {
|
||||
return '';
|
||||
}
|
||||
if (armeData.system.competence == undefined) {
|
||||
if (armeData.data.competence == undefined) {
|
||||
return 'competencecreature';
|
||||
}
|
||||
let compname = armeData.system.competence.toLowerCase();
|
||||
let compname = armeData.data.competence.toLowerCase();
|
||||
if (compname.match(/^(dague de jet|javelot|fouet|arc|arbalête|fronde|hache de jet|fléau)$/)) return '';
|
||||
|
||||
if (compname.match('hache')) return 'haches';
|
||||
@ -134,21 +137,22 @@ export class RdDItemArme extends Item {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static armeUneOuDeuxMains(armeData, aUneMain) {
|
||||
if (armeData && !armeData.system.cac) {
|
||||
armeData.system.unemain = armeData.system.unemain || !armeData.system.deuxmains;
|
||||
const uneOuDeuxMains = armeData.system.unemain && armeData.system.deuxmains;
|
||||
const containsSlash = !Number.isInteger(armeData.system.dommages) && armeData.system.dommages.includes("/");
|
||||
armeData = Misc.data(armeData);
|
||||
if (armeData && !armeData.data.cac) {
|
||||
armeData.data.unemain = armeData.data.unemain || !armeData.data.deuxmains;
|
||||
const uneOuDeuxMains = armeData.data.unemain && armeData.data.deuxmains;
|
||||
const containsSlash = !Number.isInteger(armeData.data.dommages) && armeData.data.dommages.includes("/");
|
||||
if (containsSlash) { // Sanity check
|
||||
armeData = duplicate(armeData);
|
||||
|
||||
const tableauDegats = armeData.system.dommages.split("/");
|
||||
const tableauDegats = armeData.data.dommages.split("/");
|
||||
if (aUneMain)
|
||||
armeData.system.dommagesReels = Number(tableauDegats[0]);
|
||||
armeData.data.dommagesReels = Number(tableauDegats[0]);
|
||||
else // 2 mains
|
||||
armeData.system.dommagesReels = Number(tableauDegats[1]);
|
||||
armeData.data.dommagesReels = Number(tableauDegats[1]);
|
||||
}
|
||||
else {
|
||||
armeData.system.dommagesReels = Number(armeData.system.dommages);
|
||||
armeData.data.dommagesReels = Number(armeData.data.dommages);
|
||||
}
|
||||
|
||||
if (uneOuDeuxMains != containsSlash) {
|
||||
@ -158,50 +162,51 @@ export class RdDItemArme extends Item {
|
||||
return armeData;
|
||||
}
|
||||
|
||||
static isArmeUtilisable(arme) {
|
||||
return arme.type == 'arme' && arme.system.equipe && (arme.system.resistance > 0 || arme.system.portee_courte > 0);
|
||||
static isArmeUtilisable(itemData) {
|
||||
itemData = Misc.data(itemData);
|
||||
return itemData.type == 'arme' && itemData.data.equipe && (itemData.data.resistance > 0 || itemData.data.portee_courte > 0);
|
||||
}
|
||||
|
||||
static ajoutCorpsACorps(armes, competences, carac) {
|
||||
let corpsACorps = competences.find(it => it.name == 'Corps à corps') ?? { system: { niveau: -6 } };
|
||||
let init = RdDCombatManager.calculInitiative(corpsACorps.system.niveau, carac['melee'].value);
|
||||
armes.push(RdDItemArme.mainsNues({ niveau: corpsACorps.system.niveau, initiative: init }));
|
||||
//armes.push(RdDItemArme.empoignade({ niveau: corpsACorps.system.niveau, initiative: init }));
|
||||
let corpsACorps = competences.find(it => it.name == 'Corps à corps') ?? { data: { niveau: -6 } };
|
||||
let init = RdDCombatManager.calculInitiative(corpsACorps.data.niveau, carac['melee'].value);
|
||||
armes.push(RdDItemArme.mainsNues({ niveau: corpsACorps.data.niveau, initiative: init }));
|
||||
//armes.push(RdDItemArme.empoignade({ niveau: corpsACorps.data.niveau, initiative: init }));
|
||||
}
|
||||
|
||||
static corpsACorps(mainsNuesActor) {
|
||||
static corpsACorps(actorData) {
|
||||
const corpsACorps = {
|
||||
name: 'Corps à corps',
|
||||
img: 'systems/foundryvtt-reve-de-dragon/icons/competence_corps_a_corps.webp',
|
||||
system: {
|
||||
data: {
|
||||
equipe: true,
|
||||
rapide: true,
|
||||
force: 0,
|
||||
dommages: "0",
|
||||
dommages: 0,
|
||||
dommagesReels: 0,
|
||||
mortalite: 'non-mortel',
|
||||
competence: 'Corps à corps',
|
||||
categorie_parade: 'sans-armes'
|
||||
}
|
||||
};
|
||||
mergeObject(corpsACorps.system, mainsNuesActor ?? {}, { overwrite: false });
|
||||
mergeObject(corpsACorps.data, actorData ?? {}, { overwrite: false });
|
||||
return corpsACorps;
|
||||
}
|
||||
|
||||
static mainsNues(mainsNuesActor) {
|
||||
const mainsNues = RdDItemArme.corpsACorps(mainsNuesActor)
|
||||
mainsNues.name = 'Mains nues'
|
||||
mainsNues.system.cac = 'pugilat'
|
||||
mainsNues.system.baseInit = 4
|
||||
static mainsNues(actorData) {
|
||||
const mainsNues = RdDItemArme.corpsACorps(actorData);
|
||||
mainsNues.name = 'Mains nues';
|
||||
mainsNues.data.cac = 'pugilat';
|
||||
mainsNues.data.baseInit = 4;
|
||||
return mainsNues;
|
||||
}
|
||||
|
||||
static empoignade(mainsNuesActor) {
|
||||
const empoignade = RdDItemArme.corpsACorps(mainsNuesActor)
|
||||
empoignade.name = 'Empoignade'
|
||||
empoignade.system.cac = 'empoignade'
|
||||
empoignade.system.baseInit = 3
|
||||
empoignade.system.mortalite = 'empoignade'
|
||||
return empoignade
|
||||
static empoignade(actorData) {
|
||||
const empoignade = RdDItemArme.corpsACorps(actorData);
|
||||
empoignade.name = 'Empoignade';
|
||||
empoignade.data.cac = 'empoignade';
|
||||
empoignade.data.baseInit = 3;
|
||||
empoignade.data.mortalite = 'empoignade';
|
||||
return empoignade;
|
||||
}
|
||||
}
|
||||
|
@ -8,18 +8,18 @@ const xp_par_niveau = [5, 5, 5, 10, 10, 10, 10, 15, 15, 15, 15, 20, 20, 20, 20,
|
||||
const niveau_max = xp_par_niveau.length - 10;
|
||||
/* -------------------------------------------- */
|
||||
const limitesArchetypes = [
|
||||
{ "niveau": 0, "nombreMax": 100, "reste": 100 },
|
||||
{ "niveau": 1, "nombreMax": 10, "reste": 10 },
|
||||
{ "niveau": 2, "nombreMax": 9, "reste": 9 },
|
||||
{ "niveau": 3, "nombreMax": 8, "reste": 8 },
|
||||
{ "niveau": 4, "nombreMax": 7, "reste": 7 },
|
||||
{ "niveau": 5, "nombreMax": 6, "reste": 6 },
|
||||
{ "niveau": 6, "nombreMax": 5, "reste": 5 },
|
||||
{ "niveau": 7, "nombreMax": 4, "reste": 4 },
|
||||
{ "niveau": 8, "nombreMax": 3, "reste": 3 },
|
||||
{ "niveau": 9, "nombreMax": 2, "reste": 2 },
|
||||
{ "niveau": 10, "nombreMax": 1, "reste": 1 },
|
||||
{ "niveau": 11, "nombreMax": 1, "reste": 1 }
|
||||
{ "niveau": 0, "nombreMax": 100, "nombre": 0 },
|
||||
{ "niveau": 1, "nombreMax": 10, "nombre": 0 },
|
||||
{ "niveau": 2, "nombreMax": 9, "nombre": 0 },
|
||||
{ "niveau": 3, "nombreMax": 8, "nombre": 0 },
|
||||
{ "niveau": 4, "nombreMax": 7, "nombre": 0 },
|
||||
{ "niveau": 5, "nombreMax": 6, "nombre": 0 },
|
||||
{ "niveau": 6, "nombreMax": 5, "nombre": 0 },
|
||||
{ "niveau": 7, "nombreMax": 4, "nombre": 0 },
|
||||
{ "niveau": 8, "nombreMax": 3, "nombre": 0 },
|
||||
{ "niveau": 9, "nombreMax": 2, "nombre": 0 },
|
||||
{ "niveau": 10, "nombreMax": 1, "nombre": 0 },
|
||||
{ "niveau": 11, "nombreMax": 1, "nombre": 0 }
|
||||
];
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -34,6 +34,13 @@ const categorieCompetences = {
|
||||
"lancer": { base: -8, label: "Lancer" }
|
||||
}
|
||||
|
||||
const compendiumCompetences = {
|
||||
"personnage": "foundryvtt-reve-de-dragon.competences",
|
||||
"creature": "foundryvtt-reve-de-dragon.competences-creatures",
|
||||
"entite": "foundryvtt-reve-de-dragon.competences-entites"
|
||||
};
|
||||
|
||||
|
||||
function _buildCumulXP() {
|
||||
let cumulXP = { "-11": 0 };
|
||||
let cumul = 0;
|
||||
@ -48,6 +55,12 @@ function _buildCumulXP() {
|
||||
const competence_xp_cumul = _buildCumulXP();
|
||||
|
||||
export class RdDItemCompetence extends Item {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static actorCompendium(actorType) {
|
||||
return compendiumCompetences[actorType];
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getCategorieCompetences() {
|
||||
return categorieCompetences;
|
||||
@ -63,49 +76,40 @@ export class RdDItemCompetence extends Item {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getCategorie(competence) {
|
||||
return competence?.system.categorie;
|
||||
return Misc.data(competence)?.data.categorie;
|
||||
}
|
||||
static isDraconic(competence) {
|
||||
return competence?.system.categorie == 'draconic';
|
||||
return Misc.data(competence)?.data.categorie == 'draconic';
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getVoieDraconic(competences, voie) {
|
||||
return RdDItemCompetence.findFirstItem(competences, voie, {
|
||||
preFilter: it => it.isCompetence() && RdDItemCompetence.isDraconic(it),
|
||||
description: 'Draconic',
|
||||
});
|
||||
return RdDItemCompetence.findCompetence(competences.filter(it => RdDItemCompetence.isDraconic(it)), voie);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isCompetenceArme(competence) {
|
||||
if (competence.isCompetence()) {
|
||||
switch (competence.system.categorie) {
|
||||
case 'melee':
|
||||
return !Grammar.toLowerCaseNoAccent(competence.name).includes('esquive');
|
||||
case 'tir':
|
||||
case 'lancer':
|
||||
return true;
|
||||
}
|
||||
switch (Misc.templateData(competence).categorie) {
|
||||
case 'melee':
|
||||
return Misc.data(competence).name != 'Esquive';
|
||||
case 'tir':
|
||||
case 'lancer':
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isArmeUneMain(competence) {
|
||||
return RdDItemCompetence.isCompetenceArme(competence) && competence.name.toLowerCase().includes("1 main");
|
||||
return Misc.data(competence)?.name.toLowerCase().includes("1 main");
|
||||
}
|
||||
static isArme2Main(competence) {
|
||||
return RdDItemCompetence.isCompetenceArme(competence) && competence.name.toLowerCase().includes("2 main");
|
||||
}
|
||||
|
||||
static isThanatos(competence) {
|
||||
return competence.isCompetencePersonnage() && Grammar.toLowerCaseNoAccent(competence.name).includes('thanatos');
|
||||
return Misc.data(competence)?.name.toLowerCase().includes("2 main");
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isMalusEncombrementTotal(competence) {
|
||||
return competence?.name.toLowerCase().match(/(natation|acrobatie)/) || 0;
|
||||
return Misc.data(competence)?.name.toLowerCase().match(/(natation|acrobatie)/);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -129,10 +133,11 @@ export class RdDItemCompetence extends Item {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static computeXP(competence) {
|
||||
const factor = RdDItemCompetence.isThanatos(competence) ? 2 : 1; // Thanatos compte double !
|
||||
const xpNiveau = RdDItemCompetence.computeDeltaXP(competence.system.base, competence.system.niveau ?? competence.system.base);
|
||||
const xp = competence.system.xp ?? 0;
|
||||
const xpSort = competence.system.xp_sort ?? 0;
|
||||
const itemData = Misc.data(competence);
|
||||
const factor = itemData.name.includes('Thanatos') ? 2 : 1; // Thanatos compte double !
|
||||
const xpNiveau = RdDItemCompetence.computeDeltaXP(itemData.data.base, itemData.data.niveau ?? itemData.data.base);
|
||||
const xp = itemData.data.xp ?? 0;
|
||||
const xpSort = itemData.data.xp_sort ?? 0;
|
||||
return factor * (xpNiveau + xp) + xpSort;
|
||||
}
|
||||
|
||||
@ -141,7 +146,7 @@ export class RdDItemCompetence extends Item {
|
||||
return competenceTroncs.map(
|
||||
list => list.map(name => RdDItemCompetence.findCompetence(competences, name))
|
||||
// calcul du coût xp jusqu'au niveau 0 maximum
|
||||
.map(it => RdDItemCompetence.computeDeltaXP(it?.system.base ?? -11, Math.min(it?.system.niveau ?? -11, 0)))
|
||||
.map(it => RdDItemCompetence.computeDeltaXP(it?.data.base ?? -11, Math.min(it?.data.niveau ?? -11, 0)))
|
||||
.sort(Misc.ascending())
|
||||
.splice(0, list.length - 1) // prendre toutes les valeurs sauf l'une des plus élevées
|
||||
.reduce(Misc.sum(), 0)
|
||||
@ -157,10 +162,11 @@ export class RdDItemCompetence extends Item {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static computeCompetenceXPCost(competence) {
|
||||
let xp = RdDItemCompetence.getDeltaXp(competence.system.base, competence.system.niveau ?? competence.system.base);
|
||||
xp += competence.system.xp ?? 0;
|
||||
const compData = Misc.data(competence);
|
||||
let xp = RdDItemCompetence.getDeltaXp(compData.data.base, compData.data.niveau ?? compData.data.base);
|
||||
xp += compData.data.xp ?? 0;
|
||||
if (compData.name.includes('Thanatos')) xp *= 2; /// Thanatos compte double !
|
||||
xp += competence.system.xp_sort ?? 0;
|
||||
xp += compData.data.xp_sort ?? 0;
|
||||
return xp;
|
||||
}
|
||||
|
||||
@ -169,75 +175,61 @@ export class RdDItemCompetence extends Item {
|
||||
let economie = 0;
|
||||
for (let troncList of competenceTroncs) {
|
||||
let list = troncList.map(name => RdDItemCompetence.findCompetence(competences, name))
|
||||
.sort(Misc.descending(c => this.system.niveau)); // tri du plus haut au plus bas
|
||||
.sort(Misc.descending(c => Misc.templateData(c).niveau)); // tri du plus haut au plus bas
|
||||
list.splice(0, 1); // ignorer la plus élevée
|
||||
list.map(c => c).forEach(c => {
|
||||
economie += RdDItemCompetence.getDeltaXp(c.system.base, Math.min(c.system.niveau, 0))
|
||||
list.map(c => Misc.templateData(c)).forEach(tplData => {
|
||||
economie += RdDItemCompetence.getDeltaXp(tplData.base, Math.min(tplData.niveau, 0));
|
||||
});
|
||||
}
|
||||
return economie;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static levelUp(item, stressTransforme) {
|
||||
item.system.xpNext = RdDItemCompetence.getCompetenceNextXp(item.system.niveau);
|
||||
const xpManquant = item.system.xpNext - item.system.xp;
|
||||
item.system.isLevelUp = xpManquant <= 0;
|
||||
item.system.isStressLevelUp = (xpManquant > 0 && stressTransforme >= xpManquant && item.system.niveau < item.system.niveau_archetype);
|
||||
item.system.stressXpMax = 0;
|
||||
if (xpManquant > 0 && stressTransforme > 0 && item.system.niveau < item.system.niveau_archetype) {
|
||||
item.system.stressXpMax = Math.min(xpManquant, stressTransforme);
|
||||
static levelUp(itemData, stressTransforme) {
|
||||
itemData.data.xpNext = RdDItemCompetence.getCompetenceNextXp(itemData.data.niveau);
|
||||
const xpManquant = itemData.data.xpNext - itemData.data.xp;
|
||||
itemData.data.isLevelUp = xpManquant <= 0;
|
||||
itemData.data.isStressLevelUp = (xpManquant > 0 && stressTransforme >= xpManquant && itemData.data.niveau < itemData.data.niveau_archetype);
|
||||
itemData.data.stressXpMax = 0;
|
||||
if (xpManquant > 0 && stressTransforme > 0 && itemData.data.niveau < itemData.data.niveau_archetype) {
|
||||
itemData.data.stressXpMax = Math.min(xpManquant , stressTransforme);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isVisible(item) {
|
||||
return Number(item.system.niveau) != RdDItemCompetence.getNiveauBase(item.system.categorie);
|
||||
static isVisible(itemData) {
|
||||
return Number(itemData.data.niveau) != RdDItemCompetence.getNiveauBase(itemData.data.categorie);
|
||||
}
|
||||
|
||||
static nomContientTexte(item, texte) {
|
||||
return Grammar.toLowerCaseNoAccent(item.name).includes(Grammar.toLowerCaseNoAccent(texte))
|
||||
static nomContientTexte(itemData, texte) {
|
||||
return Grammar.toLowerCaseNoAccent(itemData.name).includes(Grammar.toLowerCaseNoAccent(texte))
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isNiveauBase(item) {
|
||||
return Number(item.system.niveau) == RdDItemCompetence.getNiveauBase(item.system.categorie);
|
||||
static isNiveauBase(itemData) {
|
||||
return Number(itemData.data.niveau) == RdDItemCompetence.getNiveauBase(itemData.data.categorie);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static findCompetence(list, idOrName, options = {}) {
|
||||
if (idOrName == undefined || idOrName == "") {
|
||||
return RdDItemCompetence.sansCompetence();
|
||||
if (idOrName == undefined) {
|
||||
return undefined;
|
||||
}
|
||||
options = mergeObject(options, { preFilter: it => it.isCompetence(), description: 'compétence' }, { overwrite: false });
|
||||
return RdDItemCompetence.findFirstItem(list, idOrName, options);
|
||||
options = mergeObject(options, {
|
||||
preFilter: it => RdDItemCompetence.isCompetence(it),
|
||||
description: 'compétence',
|
||||
});
|
||||
return list.find(it => it.id == idOrName && RdDItemCompetence.isCompetence(it))
|
||||
?? Misc.findFirstLike(idOrName, list, options);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static findCompetences(list, name) {
|
||||
return Misc.findAllLike(name, list, { filter: it => it.isCompetence(), description: 'compétence' });
|
||||
return Misc.findAllLike(name, list, { filter: it => RdDItemCompetence.isCompetence(it), description: 'compétence' });
|
||||
}
|
||||
|
||||
static sansCompetence() {
|
||||
return {
|
||||
name: "Sans compétence",
|
||||
type: "competence",
|
||||
img: "systems/foundryvtt-reve-de-dragon/icons/templates/icone_parchement_vierge.webp",
|
||||
system: {
|
||||
niveau: 0,
|
||||
default_diffLibre: 0,
|
||||
base: 0,
|
||||
categorie: "Aucune",
|
||||
description: "",
|
||||
descriptionmj: "",
|
||||
defaut_carac: "",
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static findFirstItem(list, idOrName, options) {
|
||||
return list.find(it => it.id == idOrName && options.preFilter(it))
|
||||
?? Misc.findFirstLike(idOrName, list, options);
|
||||
static isCompetence(item) {
|
||||
return item.type == 'competence' || item.type == 'competencecreature';
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -267,47 +259,18 @@ export class RdDItemCompetence extends Item {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static computeResumeArchetype(competences) {
|
||||
const computed = duplicate(limitesArchetypes);
|
||||
competences.map(it => Math.max(0, it.system.niveau_archetype))
|
||||
.filter(n => n > 0)
|
||||
.forEach(n => {
|
||||
computed[n] = computed[n] ?? { niveau: n, nombreMax: 0, reste: 0 };
|
||||
computed[n].reste = computed[n].reste - 1;
|
||||
const archetype = RdDItemCompetence.getLimitesArchetypes();
|
||||
competences.map(it => Math.max(0, Misc.templateData(it).niveau_archetype))
|
||||
.forEach(niveau => {
|
||||
archetype[niveau] = archetype[niveau] ?? { "niveau": niveau, "nombreMax": 0, "nombre": 0 };
|
||||
archetype[niveau].nombre = (archetype[niveau]?.nombre ?? 0) + 1;
|
||||
});
|
||||
return computed.filter(it => it.reste > 0 && it.niveau > 0);
|
||||
return archetype;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static triVisible(competences) {
|
||||
return competences.filter(it => it.system.isVisible)
|
||||
.sort((a, b) => RdDItemCompetence.compare(a, b))
|
||||
}
|
||||
|
||||
static $positionTri(comp) {
|
||||
if (comp.name.startsWith("Survie")) {
|
||||
if (comp.name.includes("Cité")) return 0;
|
||||
if (comp.name.includes("Extérieur")) return 1;
|
||||
return 2;
|
||||
}
|
||||
if (comp.system.categorie.startsWith("melee")) {
|
||||
if (comp.name.includes("Corps")) return 0;
|
||||
if (comp.name.includes("Dague")) return 1;
|
||||
if (comp.name.includes("Esquive")) return 2;
|
||||
return 3;
|
||||
}
|
||||
if (comp.system.categorie.startsWith("draconic")) {
|
||||
if (comp.name.includes("Oniros")) return 0;
|
||||
if (comp.name.includes("Hypnos")) return 1;
|
||||
if (comp.name.includes("Narcos")) return 2;
|
||||
if (comp.name.includes("Thanatos")) return 3;
|
||||
return 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static compare(a, b) {
|
||||
const diff = RdDItemCompetence.$positionTri(a) - RdDItemCompetence.$positionTri(b);
|
||||
return diff ? diff : a.name.localeCompare(b.name);
|
||||
static getLimitesArchetypes() {
|
||||
return duplicate(limitesArchetypes);
|
||||
}
|
||||
|
||||
}
|
@ -1,53 +1,51 @@
|
||||
|
||||
import { RdDCombatManager } from "./rdd-combat.js";
|
||||
import { Misc } from "./misc.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class RdDItemCompetenceCreature extends Item {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static setRollDataCreature(rollData) {
|
||||
rollData.competence = rollData.competence
|
||||
rollData.carac = { "carac_creature": { label: rollData.competence.name, value: rollData.competence.system.carac_value } }
|
||||
rollData.competence.system.defaut_carac = "carac_creature"
|
||||
rollData.competence.system.categorie = "creature"
|
||||
rollData.competence = Misc.data(rollData.competence);
|
||||
rollData.carac = { "carac_creature": { label: rollData.competence.name, value: rollData.competence.data.carac_value } };
|
||||
rollData.competence.data.defaut_carac = "carac_creature"
|
||||
rollData.competence.data.categorie = "creature"
|
||||
rollData.selectedCarac = rollData.carac.carac_creature
|
||||
if (rollData.competence.system.iscombat) {
|
||||
rollData.arme = RdDItemCompetenceCreature.armeNaturelle(rollData.competence);
|
||||
if (rollData.competence.data.iscombat) {
|
||||
rollData.arme = RdDItemCompetenceCreature.toActionArme(rollData.competence);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static armeNaturelle(competencecreature) {
|
||||
if (RdDItemCompetenceCreature.isCompetenceAttaque(competencecreature)) {
|
||||
// si c'est un Item compétence: cloner pour ne pas modifier lma compétence
|
||||
let arme = (competencecreature instanceof Item) ? competencecreature.clone(): competencecreature;
|
||||
mergeObject(arme.system,
|
||||
static toActionArme(item) {
|
||||
if (RdDItemCompetenceCreature.isCompetenceAttaque(item)) {
|
||||
// si c'est un Item compétence: cloner pour ne pas modifier la compétence
|
||||
let arme = Misc.data( (item instanceof Item) ? item.clone(): item);
|
||||
mergeObject(arme.data,
|
||||
{
|
||||
competence: arme.name,
|
||||
initiative: RdDCombatManager.calculInitiative(competencecreature.system.niveau, competencecreature.system.carac_value),
|
||||
niveau: competencecreature.system.niveau,
|
||||
equipe: true,
|
||||
resistance: 100,
|
||||
dommagesReels: arme.system.dommages,
|
||||
equipe: true,
|
||||
dommagesReels: arme.data.dommages,
|
||||
penetration: 0,
|
||||
force: 0,
|
||||
rapide: true,
|
||||
cac: competencecreature.system.isnaturelle ? "naturelle" : "",
|
||||
action: 'attaque'
|
||||
});
|
||||
return arme;
|
||||
}
|
||||
console.error("RdDItemCompetenceCreature.toActionArme(", competencecreature, ") : impossible de transformer l'Item en arme");
|
||||
console.error("RdDItemCompetenceCreature.toActionArme(", item, ") : impossible de transformer l'Item en arme");
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isCompetenceAttaque(item) {
|
||||
return item.type == 'competencecreature' && item.system.iscombat;
|
||||
static isCompetenceAttaque(itemData) {
|
||||
itemData = Misc.data(itemData);
|
||||
return itemData.type == 'competencecreature' && itemData.data.iscombat;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isCompetenceParade(item) {
|
||||
return item.type == 'competencecreature' && item.system.categorie_parade !== "";
|
||||
static isCompetenceParade(itemData) {
|
||||
itemData = Misc.data(itemData);
|
||||
return itemData.type == 'competencecreature' && itemData.data.isparade;
|
||||
}
|
||||
}
|
||||
|
@ -1,60 +0,0 @@
|
||||
import { RdDItemSheet } from "./item-sheet.js";
|
||||
import { RdDSheetUtility } from "./rdd-sheet-utility.js";
|
||||
import { RdDUtility } from "./rdd-utility.js";
|
||||
|
||||
export class RdDConteneurItemSheet extends RdDItemSheet {
|
||||
|
||||
static get ITEM_TYPE() { return "conteneur" };
|
||||
|
||||
async getData() {
|
||||
const formData = await super.getData();
|
||||
if (this.actor) {
|
||||
this.prepareConteneurData(formData);
|
||||
}
|
||||
return formData;
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
if (!this.options.editable) return;
|
||||
|
||||
this.html.find('.conteneur-name a').click(async event => {
|
||||
RdDUtility.toggleAfficheContenu(RdDSheetUtility.getItemId(event));
|
||||
this.render(true);
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
prepareConteneurData(formData) {
|
||||
RdDUtility.filterEquipementParType(formData, this.actor.itemTypes);
|
||||
|
||||
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.objets);
|
||||
formData.subItems = formData.conteneurs.find(it => it._id == this.item.id)?.subItems;
|
||||
}
|
||||
|
||||
async _onDragStart(event) {
|
||||
console.log("_onDragStart", event);
|
||||
if (event.target.classList.contains("entity-link")) return;
|
||||
|
||||
const itemId = event.srcElement?.attributes["data-item-id"].value;
|
||||
const item = this.actor.items.get(itemId);
|
||||
// Create drag data
|
||||
const dragData = {
|
||||
actorId: this.actor.id,
|
||||
type: "Item",
|
||||
data: item.system
|
||||
};
|
||||
|
||||
event.dataTransfer.setData("text/plain", JSON.stringify(dragData));
|
||||
}
|
||||
|
||||
async _onDropItem(event, dragData) {
|
||||
if (this.actor) {
|
||||
const dropParams = RdDSheetUtility.prepareItemDropParameters(this.item.id, this.actor, dragData, this.objetVersConteneur);
|
||||
await this.actor.processDropItem(dropParams);
|
||||
await this.render(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
import { EnvironmentSheetHelper } from "./environnement.js";
|
||||
import { RdDItemSheet } from "./item-sheet.js";
|
||||
import { RdDUtility } from "./rdd-utility.js";
|
||||
|
||||
export class RdDFauneItemSheet extends RdDItemSheet {
|
||||
|
||||
static get ITEM_TYPE() { return "faune" };
|
||||
|
||||
static get defaultOptions() {
|
||||
return EnvironmentSheetHelper.defaultOptions(super.defaultOptions);
|
||||
}
|
||||
|
||||
setPosition(options = {}) {
|
||||
return EnvironmentSheetHelper.setPosition(this, super.setPosition(options));
|
||||
}
|
||||
|
||||
async getData() {
|
||||
const formData = await super.getData();
|
||||
return await EnvironmentSheetHelper.getData(this, formData);
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
if (!this.options.editable) return;
|
||||
|
||||
EnvironmentSheetHelper.activateListeners(this);
|
||||
|
||||
html.find("a.linked-actor-delete").click(event => this.onDeleteLinkedActor());
|
||||
html.find("a.preparer-nourriture").click(event => this.preparerNourriture(event));
|
||||
html.find("a.manger-nourriture").click(event => this.mangerNourriture(event));
|
||||
}
|
||||
|
||||
async _onDropActor(event, dragData) {
|
||||
console.log('faune:dropActor', event, dragData)
|
||||
const linkedActor = fromUuidSync(dragData.uuid);
|
||||
if (linkedActor?.pack) {
|
||||
this.item.update({
|
||||
'system.actor.pack': linkedActor.pack,
|
||||
'system.actor.id': linkedActor._id,
|
||||
'system.actor.name': linkedActor.name
|
||||
});
|
||||
}
|
||||
else {
|
||||
ui.notifications.warn(`${linkedActor.name} ne provient pas d'un compendium.
|
||||
<br>Choisissez une créature du compendium pour représenter un élément de faune générique`)
|
||||
}
|
||||
}
|
||||
async onDeleteLinkedActor() {
|
||||
this.item.update({
|
||||
'system.actor.pack': '',
|
||||
'system.actor.id': '',
|
||||
'system.actor.name': ''
|
||||
});
|
||||
}
|
||||
|
||||
async preparerNourriture(event) {
|
||||
if (this.actor) {
|
||||
await this.actor.preparerNourriture(this.item);
|
||||
}
|
||||
}
|
||||
async mangerNourriture(event) {
|
||||
if (this.actor) {
|
||||
await this.actor.mangerNourriture(this.item);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
import { EnvironmentSheetHelper } from "./environnement.js";
|
||||
import { RdDItemSheet } from "./item-sheet.js";
|
||||
|
||||
export class RdDHerbeItemSheet extends RdDItemSheet {
|
||||
|
||||
static get ITEM_TYPE() { return "herbe" };
|
||||
|
||||
static get defaultOptions() {
|
||||
return EnvironmentSheetHelper.defaultOptions(super.defaultOptions);
|
||||
}
|
||||
|
||||
setPosition(options = {}) {
|
||||
return EnvironmentSheetHelper.setPosition(this, super.setPosition(options));
|
||||
}
|
||||
|
||||
async getData() {
|
||||
const formData = await super.getData();
|
||||
return await EnvironmentSheetHelper.getData(this, formData);
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
EnvironmentSheetHelper.activateListeners(this);
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
import { EnvironmentSheetHelper } from "./environnement.js";
|
||||
import { RdDItemSheet } from "./item-sheet.js";
|
||||
|
||||
export class RdDIngredientItemSheet extends RdDItemSheet {
|
||||
|
||||
static get ITEM_TYPE() { return "ingredient" };
|
||||
|
||||
static get defaultOptions() {
|
||||
return EnvironmentSheetHelper.defaultOptions(super.defaultOptions);
|
||||
}
|
||||
|
||||
setPosition(options = {}) {
|
||||
return EnvironmentSheetHelper.setPosition(this, super.setPosition(options));
|
||||
}
|
||||
|
||||
async getData() {
|
||||
const formData = await super.getData();
|
||||
return await EnvironmentSheetHelper.getData(this, formData);
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
EnvironmentSheetHelper.activateListeners(this);
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@ export class RdDItemMeditation {
|
||||
static calculDifficulte(rollData) {
|
||||
if (rollData.meditation) {
|
||||
// Malus permanent éventuel
|
||||
let diff = rollData.meditation.system.malus ?? 0;
|
||||
let diff = rollData.meditation.data.malus ?? 0;
|
||||
if (!rollData.conditionMeditation.isHeure) diff -= 2;
|
||||
if (!rollData.conditionMeditation.isVeture) diff -= 2;
|
||||
if (!rollData.conditionMeditation.isComportement) diff -= 2;
|
||||
|
@ -1,118 +1,61 @@
|
||||
import { Misc } from "./misc.js";
|
||||
import { LOG_HEAD } from "./constants.js";
|
||||
|
||||
const MONNAIE_ETAIN = {
|
||||
name: "Denier (étain)", type: 'monnaie',
|
||||
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_etain_poisson.webp",
|
||||
system: { quantite: 0, cout: 0.01, encombrement: 0.001, description: "" }
|
||||
};
|
||||
const MONNAIE_BRONZE = {
|
||||
name: "Sou (bronze)", type: 'monnaie',
|
||||
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_bronze_epees.webp",
|
||||
system: { quantite: 0, cout: 0.10, encombrement: 0.002, description: "" }
|
||||
};
|
||||
const MONNAIE_ARGENT = {
|
||||
name: "Sol (argent)", type: 'monnaie',
|
||||
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_argent_sol.webp",
|
||||
system: { quantite: 0, cout: 1, encombrement: 0.003, description: "" }
|
||||
};
|
||||
const MONNAIE_OR = {
|
||||
name: "Dreagon (or)", type: 'monnaie',
|
||||
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_or_sol.webp",
|
||||
system: { quantite: 0, cout: 10, encombrement: 0.004, description: "" }
|
||||
};
|
||||
|
||||
const MONNAIES_STANDARD = [MONNAIE_ETAIN, MONNAIE_BRONZE, MONNAIE_ARGENT, MONNAIE_OR];
|
||||
const VALEUR_DENIERS = sols => Math.max(Math.floor((sols ?? 0) * 100), 0);
|
||||
const monnaiesData = [
|
||||
{
|
||||
name: "Etain (1 denier)", type: 'monnaie',
|
||||
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_etain_poisson.webp",
|
||||
data: { quantite: 0, valeur_deniers: 1, encombrement: 0.001, description: "" }
|
||||
},
|
||||
{
|
||||
name: "Bronze (10 deniers)", type: 'monnaie',
|
||||
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_bronze_epees.webp",
|
||||
data: { quantite: 0, valeur_deniers: 10, encombrement: 0.002, description: "" }
|
||||
},
|
||||
{
|
||||
name: "Argent (1 sol)", type: 'monnaie',
|
||||
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_argent_sol.webp",
|
||||
data: { quantite: 0, valeur_deniers: 100, encombrement: 0.003, description: "" }
|
||||
},
|
||||
{
|
||||
name: "Or (10 sols)", type: 'monnaie',
|
||||
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_or_sol.webp",
|
||||
data: { quantite: 0, valeur_deniers: 1000, encombrement: 0.004, description: "" }
|
||||
}
|
||||
]
|
||||
|
||||
export class Monnaie {
|
||||
|
||||
static monnaiesStandard() {
|
||||
return MONNAIES_STANDARD;
|
||||
static isSystemMonnaie(item) {
|
||||
let present = monnaiesData.find(monnaie => monnaie.data.valeur_deniers == Misc.data(item)?.data?.valeur_deniers);
|
||||
return present;
|
||||
}
|
||||
|
||||
static monnaiesManquantes(actor) {
|
||||
const disponibles = actor.itemTypes['monnaie'];
|
||||
const manquantes = MONNAIES_STANDARD.filter(standard => !disponibles.find(disponible => Monnaie.deValeur(disponible, standard.system?.cout)));
|
||||
if (manquantes.length > 0) {
|
||||
console.error(`${LOG_HEAD} monnaiesManquantes pour ${actor.name}`, manquantes, ' avec monnaies', disponibles, MONNAIES_STANDARD);
|
||||
}
|
||||
return manquantes;
|
||||
static monnaiesData() {
|
||||
return monnaiesData;
|
||||
}
|
||||
|
||||
static deValeur(monnaie, valeur) {
|
||||
return VALEUR_DENIERS(valeur) == VALEUR_DENIERS(monnaie.system.cout)
|
||||
static filtrerMonnaies(items) {
|
||||
return items.filter(it => Misc.data(it).type == 'monnaie');
|
||||
}
|
||||
|
||||
static triValeurEntiere() {
|
||||
return Misc.ascending(item => VALEUR_DENIERS(item.system.cout))
|
||||
static monnaiesManquantes(items) {
|
||||
const valeurs = Monnaie.filtrerMonnaies(items)
|
||||
.map(it => Misc.templateData(it).valeur_deniers);
|
||||
const manquantes = monnaiesData.filter(monnaie => !valeurs.find(v => v != Misc.templateData(monnaie).valeur_deniers));
|
||||
//const manquantes = monnaiesData.filter(monnaie => !valeurs.find(v => v != Misc.templateData(monnaie).valeur_deniers) );
|
||||
//console.log("Valeurs : ", valeurs, manquantes);
|
||||
return []; //manquantes;
|
||||
}
|
||||
|
||||
static async creerMonnaiesStandard(actor) {
|
||||
await actor.createEmbeddedDocuments('Item', MONNAIES_STANDARD, { renderSheet: false });
|
||||
static deValeur(monnaie, v) {
|
||||
return v != monnaie.data.valeur_deniers;
|
||||
}
|
||||
|
||||
static async creerMonnaiesDeniers(actor, fortune) {
|
||||
await actor.createEmbeddedDocuments('Item', [Monnaie.creerDeniers(fortune)], { renderSheet: false });
|
||||
static arrondiDeniers(sols) {
|
||||
return sols.toFixed(2);
|
||||
}
|
||||
|
||||
static creerDeniers(fortune) {
|
||||
const deniers = duplicate(MONNAIE_ETAIN);
|
||||
deniers.system.quantite = fortune;
|
||||
return deniers;
|
||||
}
|
||||
|
||||
static getFortune(actor) {
|
||||
if (actor) {
|
||||
Monnaie.validerMonnaies(actor);
|
||||
return actor.itemTypes['monnaie']
|
||||
.map(m => Number(m.system.cout) * Number(m.system.quantite))
|
||||
.reduce(Misc.sum(), 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static getFortuneSolsDeniers(actor) {
|
||||
const fortune = Monnaie.getFortune(actor);
|
||||
return {
|
||||
sols: Math.floor(fortune),
|
||||
deniers: Math.round(100 * (fortune - Math.floor(fortune)))
|
||||
};
|
||||
}
|
||||
|
||||
static async optimiserFortune(actor, fortune) {
|
||||
let resteEnDeniers = Math.round(fortune * 100);
|
||||
let monnaies = actor.itemTypes['monnaie'];
|
||||
let updates = [];
|
||||
Monnaie.validerMonnaies(actor);
|
||||
|
||||
let parValeur = Misc.classifyFirst(monnaies, it => VALEUR_DENIERS(it.system.cout));
|
||||
for (let valeurDeniers of [1000, 100, 10, 1]) {
|
||||
const itemPiece = parValeur[valeurDeniers];
|
||||
if (itemPiece) {
|
||||
const quantite = Math.floor(resteEnDeniers / valeurDeniers);
|
||||
if (quantite != itemPiece.system.quantite) {
|
||||
updates.push({ _id: parValeur[valeurDeniers].id, 'system.quantite': quantite });
|
||||
}
|
||||
resteEnDeniers -= quantite * valeurDeniers;
|
||||
}
|
||||
}
|
||||
console.log('Monnaie.optimiserFortune', actor.name, 'total', fortune, 'parValeur', parValeur, 'updates', updates, 'reste', resteEnDeniers);
|
||||
if (updates.length > 0) {
|
||||
await actor.updateEmbeddedDocuments('Item', updates);
|
||||
}
|
||||
if (resteEnDeniers > 0) {
|
||||
// créer le reste en deniers fortune en deniers
|
||||
await Monnaie.creerMonnaiesDeniers(actor, resteEnDeniers);
|
||||
}
|
||||
}
|
||||
|
||||
static validerMonnaies(actor) {
|
||||
actor.itemTypes['monnaie'].filter(it => VALEUR_DENIERS(it.system.cout) == 0)
|
||||
.map(it => `La monnaie ${it.name} de l'acteur ${actor.name} a une valeur de 0!`)
|
||||
.forEach(message => {
|
||||
ui.notifications.warn(message);
|
||||
console.warn(message);
|
||||
});
|
||||
static triValeurDenier() {
|
||||
return Misc.ascending(item => Misc.data(item).data.valeur_deniers);
|
||||
}
|
||||
}
|
||||
|
@ -1,78 +0,0 @@
|
||||
import { RdDRencontre } from "./item-rencontre.js";
|
||||
import { RdDItemSheet } from "./item-sheet.js";
|
||||
|
||||
export class RdDRencontreItemSheet extends RdDItemSheet {
|
||||
|
||||
static get ITEM_TYPE() { return "rencontre" };
|
||||
|
||||
static get defaultOptions() {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }]
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
setPosition(options = {}) {
|
||||
const position = super.setPosition(options);
|
||||
const sheetHeader = this.element.find(".sheet-header");
|
||||
const sheetBody = this.element.find(".sheet-body");
|
||||
sheetBody.css("height", position.height - sheetHeader[0].clientHeight)
|
||||
return position;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async getData() {
|
||||
const formData = await super.getData();
|
||||
mergeObject(formData, {
|
||||
effets: {
|
||||
succes: {
|
||||
liste: RdDRencontre.getEffetsSucces(),
|
||||
select: RdDRencontre.mapEffets(this.item.system.succes.effets)
|
||||
},
|
||||
echec: {
|
||||
liste: RdDRencontre.getEffetsEchec(),
|
||||
select: RdDRencontre.mapEffets(this.item.system.echec.effets)
|
||||
}
|
||||
}
|
||||
});
|
||||
return formData;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
if (!this.options.editable) return;
|
||||
this.html.find("a.effet-add").click(event => this.onAddEffet(event));
|
||||
this.html.find("a.effet-delete").click(event => this.onDeleteEffet(event));
|
||||
}
|
||||
|
||||
async onAddEffet(event) {
|
||||
const resultat = this.html.find(event.currentTarget)?.data("effet-resultat");
|
||||
const keyEffets = `system.${resultat}.effets`;
|
||||
|
||||
const code = this.html.find(event.currentTarget)?.data("effet-code");
|
||||
const liste = RdDRencontre.getListeEffets(this.item, resultat);
|
||||
liste.push(code);
|
||||
|
||||
await this._updateEffetsRencontre(keyEffets, liste);
|
||||
}
|
||||
|
||||
async onDeleteEffet(event) {
|
||||
const resultat = this.html.find(event.currentTarget)?.data("effet-resultat");
|
||||
const keyEffets = `system.${resultat}.effets`;
|
||||
|
||||
const pos = this.html.find(event.currentTarget)?.data("effet-pos");
|
||||
const liste = RdDRencontre.getListeEffets(this.item, resultat);
|
||||
liste.splice(pos, 1);
|
||||
|
||||
await this._updateEffetsRencontre(keyEffets, liste);
|
||||
}
|
||||
|
||||
async _updateEffetsRencontre(key, liste) {
|
||||
const updates = {};
|
||||
updates[key] = liste;
|
||||
this.item.update(updates);
|
||||
}
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
import { EffetsRencontre } from "./effets-rencontres.js";
|
||||
|
||||
const tableEffets = [
|
||||
{ code: "messager", resultat: "succes", description: "Envoie un message à (force) cases", method: EffetsRencontre.messager },
|
||||
{ code: "passeur", resultat: "succes", description: "Déplacer le demi-rêve à (force) cases", method: EffetsRencontre.passeur},
|
||||
{ code: "reve+f", resultat: "succes", description: "Gain de (force) points de rêve" , method: EffetsRencontre.reve_plus_force},
|
||||
{ code: "teleport", resultat: "succes", description: "Déplacer le demi-rêve (même type)", method: EffetsRencontre.teleportation_typecase },
|
||||
{ code: "part+tete", resultat: "succes", description: "Tête de dragon sur réussite particulière", method: EffetsRencontre.rdd_part_tete },
|
||||
{ code: "part+xp", resultat: "succes", description: "Expérience sur réussite particulière", method: EffetsRencontre.experience_particuliere },
|
||||
{ code: "seuil", resultat: "succes", description: "Récupération de seuil de rêve", method: EffetsRencontre.regain_seuil },
|
||||
|
||||
{ code: "reve-1", resultat: "echec", description: "Perte de 1 point de rêve", method: EffetsRencontre.reve_moins_1 },
|
||||
{ code: "reve-f", resultat: "echec", description: "Perte de (force) points de rêve", method: EffetsRencontre.reve_moins_force },
|
||||
{ code: "vie-1", resultat: "echec", description: "Perte de 1 point de vie", method: EffetsRencontre.vie_moins_1 },
|
||||
{ code: "reinsere", resultat: "echec", description: "Réinsertion aléatoire", method: EffetsRencontre.reinsertion },
|
||||
{ code: "persistant", resultat: "echec", description: "Bloque le demi-rêve", method: EffetsRencontre.rencontre_persistante },
|
||||
{ code: "teleport-aleatoire", resultat: "echec", description: "Déplacement aléatoire (même type)", method: EffetsRencontre.teleportation_aleatoire_typecase },
|
||||
{ code: "aleatoire", resultat: "echec", description: "Déplacement aléatoire", method: EffetsRencontre.deplacement_aleatoire },
|
||||
{ code: "sort-aleatoire", resultat: "echec", description: "Déclenche un sort en réserve aléatoire", method: EffetsRencontre.sort_aleatoire },
|
||||
{ code: "rompu", resultat: "echec", description: "Demi-rêve interrompu", method: EffetsRencontre.demireve_rompu },
|
||||
{ code: "echec-queue", resultat: "echec", description: "Queue(s) de dragon sur échec", method: EffetsRencontre.rdd_echec_queue },
|
||||
|
||||
{ code: "reve+1", resultat: "succes", description: "Gain de 1 point de rêve", method: EffetsRencontre.reve_plus_1 },
|
||||
{ code: "vie-f", resultat: "echec", description: "Perte de (force) points de vie", method: EffetsRencontre.vie_moins_force },
|
||||
{ code: "moral+1", resultat: "succes", description: "Gain de 1 point de moral", method: EffetsRencontre.moral_plus_1 },
|
||||
{ code: "moral-1", resultat: "echec", description: "Perte de 1 point de moral", method: EffetsRencontre.moral_moins_1 },
|
||||
{ code: "xpsort+f", resultat: "succes", description: "Gain de (force) xp sort", method: EffetsRencontre.xp_sort_force },
|
||||
{ code: "endurance-1", resultat: "echec", description: "Perte de 1 point d'endurance", method: EffetsRencontre.end_moins_1 },
|
||||
{ code: "endurance-f", resultat: "echec", description: "Perte de (force) points d'endurance", method: EffetsRencontre.end_moins_force },
|
||||
{ code: "fatigue+1", resultat: "echec", description: "Coup de fatigue de 1 point", method: EffetsRencontre.fatigue_plus_1},
|
||||
{ code: "fatigue+f", resultat: "echec", description: "Coup de fatigue de 1 (force) points", method: EffetsRencontre.fatigue_plus_force },
|
||||
{ code: "fatigue-1", resultat: "succes", description: "Récupération de 1 point de fatigue", method: EffetsRencontre.fatigue_moins_1},
|
||||
{ code: "fatigue-f", resultat: "succes", description: "Récupération de 1 (force) points de fatigue", method: EffetsRencontre.fatigue_moins_force },
|
||||
{ code: "perte-chance", resultat: "echec", description: "Perte de chance actuelle", method: EffetsRencontre.perte_chance },
|
||||
{ code: "stress+1", resultat: "succes", description: "Gain de 1 point de stress", method: EffetsRencontre.stress_plus_1 },
|
||||
// { code: "epart-souffle", resultat: "echec", description: "Souffle de dragon sur échec particulier" },
|
||||
];
|
||||
|
||||
export class RdDRencontre {
|
||||
|
||||
static getEffetsSucces() { return RdDRencontre.getEffets("succes"); }
|
||||
static getEffetsEchec() { return RdDRencontre.getEffets("echec"); }
|
||||
static getEffets(resultat) {
|
||||
return tableEffets.filter(e => resultat == e.resultat);
|
||||
}
|
||||
|
||||
static mapEffets(liste) {
|
||||
return liste.map(it => RdDRencontre.getEffet(it));
|
||||
}
|
||||
|
||||
static getListeEffets(item, reussite) {
|
||||
if (reussite == 'echec') {
|
||||
return [...item.system.echec.effets];
|
||||
}
|
||||
if (reussite == 'succes') {
|
||||
return [...item.system.succes.effets];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
static getEffet(code) {
|
||||
return tableEffets.find(it => code == it.code)
|
||||
}
|
||||
|
||||
static async appliquer(codes, tmrDialog, rencData) {
|
||||
for(const effet of RdDRencontre.mapEffets(codes)){
|
||||
await effet.method(tmrDialog, rencData);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
import { RdDItemSheet } from "./item-sheet.js";
|
||||
import { Misc } from "./misc.js";
|
||||
import { RdDUtility } from "./rdd-utility.js";
|
||||
import { SystemCompendiums } from "./settings/system-compendiums.js";
|
||||
import { DialogItemAchat } from "./dialog-item-achat.js";
|
||||
import { RdDItem } from "./item.js";
|
||||
import { RdDItemService } from "./item-service.js";
|
||||
|
||||
export class RdDServiceItemSheet extends RdDItemSheet {
|
||||
|
||||
static get ITEM_TYPE() { return "service" };
|
||||
|
||||
async getData() {
|
||||
const formData = await super.getData();
|
||||
formData.disabled = formData.isGM || formData.isOwned ? '' : 'disabled';
|
||||
return formData;
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
this.html.find('a.rdd-world-content-link').click(async event => {
|
||||
const itemRef = this.getItemRef(event);
|
||||
game.items.get(itemRef.id)?.sheet.render(true)
|
||||
});
|
||||
|
||||
this.html.find('a.sub-item-acheter').click(async event => {
|
||||
const subItem = this.item.findRefItem(this.getItemRef(event));
|
||||
await this.item.acheter(RdDUtility.getSelectedActor(), subItem);
|
||||
});
|
||||
|
||||
if (!this.options.editable) return;
|
||||
|
||||
this.html.find('a.sub-item-vendre').click(async event => {
|
||||
const subItem = this.item.findRefItem(this.getItemRef(event));
|
||||
await this.item.vendre(subItem);
|
||||
});
|
||||
|
||||
this.html.find('a.sub-item-delete').click(async event => {
|
||||
await this.item.removeRefItem(this.getItemRef(event));
|
||||
});
|
||||
|
||||
this.html.find('a.sub-item-quantite-moins').click(async event => await this.item.increaseRefItemQuantite(this.getItemRef(event), -1))
|
||||
this.html.find('a.sub-item-quantite-plus').click(async event => await this.item.increaseRefItemQuantite(this.getItemRef(event), 1))
|
||||
this.html.find('input.sub-item-quantite').change(async event => {
|
||||
const newQuantite = Math.max(0, Number.parseInt(this.html.find(event.currentTarget).val()));
|
||||
await this.item.updateRefItem(this.getItemRef(event), it => it.system.quantite = newQuantite);
|
||||
})
|
||||
this.html.find('input.sub-item-cout').change(async event => {
|
||||
const newCout = Math.max(0, Number(this.html.find(event.currentTarget).val()));
|
||||
await this.item.updateRefItem(this.getItemRef(event), it => it.system.cout = newCout);
|
||||
})
|
||||
this.html.find('a.sub-item-info-add').click(__ =>
|
||||
ui.notifications.info(`Utiliser le glisser-déposer pour ajouter des objets depuis un compendium ou les objets du monde`)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
async _onDropItem(event, dragData) {
|
||||
let linkedItem = fromUuidSync(dragData.uuid);
|
||||
const existing = this.item.system.items.find(it => it.pack == linkedItem.pack && it.id == linkedItem.id && it.type == linkedItem.type);
|
||||
if (existing) {
|
||||
ui.notifications.warn(`${this.item.name} contient déjà un ${existing.name}`);
|
||||
return;
|
||||
}
|
||||
if (linkedItem.pack) {
|
||||
linkedItem = await SystemCompendiums.loadDocument(linkedItem);
|
||||
}
|
||||
if (linkedItem.isInventaire()) {
|
||||
await this.item.addRefItem(RdDItemService.createSubItem(linkedItem));
|
||||
}
|
||||
else {
|
||||
ui.notifications.warn(`${this.item.name} ne peut pas proposer à la vente de ${Misc.typeName('Item', linkedItem.type)}: ${linkedItem.name}`);
|
||||
}
|
||||
}
|
||||
|
||||
getItemRef(event) {
|
||||
const itemRow = this.html.find(event.currentTarget)?.parents('.item.service-item');
|
||||
return { id: itemRow?.data("item-id"), pack: itemRow?.data("pack") ?? undefined }
|
||||
}
|
||||
}
|
@ -1,140 +0,0 @@
|
||||
import { DialogItemAchat } from "./dialog-item-achat.js";
|
||||
import { RdDItem } from "./item.js";
|
||||
import { Misc } from "./misc.js";
|
||||
|
||||
export class RdDItemService extends RdDItem {
|
||||
|
||||
static get defaultIcon() {
|
||||
return "systems/foundryvtt-reve-de-dragon/icons/items/services.webp";
|
||||
}
|
||||
|
||||
/** @override*/
|
||||
getUserLevel(user) {
|
||||
const level = super.getUserLevel(user);
|
||||
if (level == CONST.DOCUMENT_OWNERSHIP_LEVELS.NONE) {
|
||||
// si quelqu'un a accès au lien d'un service, il peut le voir
|
||||
return CONST.DOCUMENT_OWNERSHIP_LEVELS.LIMITED;
|
||||
}
|
||||
return level;
|
||||
}
|
||||
|
||||
isService() { return true; }
|
||||
getChatItemTemplate() { return 'systems/foundryvtt-reve-de-dragon/templates/post-item-service.html'; }
|
||||
getProprietes() { return []; }
|
||||
|
||||
getServiceItem(itemRef) {
|
||||
if (this.isService()) {
|
||||
return this.system.items.find(it => it.id == itemRef.id && it.pack == itemRef.pack);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getQuantiteDisponible(itemRef, max) {
|
||||
if (this.system.illimite) {
|
||||
return max;
|
||||
}
|
||||
const subItem = this.getServiceItem(itemRef);
|
||||
return subItem?.system.quantite ?? 0;
|
||||
}
|
||||
|
||||
async venteRefItem(ref, quantite, cout) {
|
||||
if (this.actor) {
|
||||
await this.actor.ajouterSols(cout);
|
||||
}
|
||||
await this.increaseRefItemQuantite(ref, -quantite);
|
||||
}
|
||||
|
||||
async vendre(subItem) {
|
||||
const item = await RdDItem.getCorrespondingItem(subItem);
|
||||
const quantiteMax = this.system.illimite ? undefined : subItem.system.quantite;
|
||||
await item.proposerVente({ service: this, quantiteMax });
|
||||
}
|
||||
|
||||
async acheter(acheteur, subItem) {
|
||||
if (!acheteur) {
|
||||
ui.notifications.warn(`Pas d'acheteur sélectionné`);
|
||||
return;
|
||||
}
|
||||
const nbLots = this.system.illimite ? 1 : subItem.system.quantite;
|
||||
if (nbLots <= 0) {
|
||||
ui.notifications.warn(`${this.name} n'a plus de ${subItem.name} en vente`);
|
||||
return;
|
||||
}
|
||||
|
||||
await DialogItemAchat.onAcheter({
|
||||
item: await RdDItem.getCorrespondingItem(subItem),
|
||||
acheteur,
|
||||
service: this,
|
||||
quantiteIllimite: this.system.illimite,
|
||||
nbLots,
|
||||
tailleLot: 1,
|
||||
prixLot: subItem.system.cout
|
||||
});
|
||||
}
|
||||
|
||||
static createSubItem(linkedItem) {
|
||||
return {
|
||||
id: linkedItem.id,
|
||||
pack: linkedItem.pack,
|
||||
name: linkedItem.name,
|
||||
img: linkedItem.img,
|
||||
system: {
|
||||
quantite: 1,
|
||||
cout: linkedItem.system.cout ?? 0
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static matchRefItem({ id, pack }) {
|
||||
return it => it.id == id && (pack ? (it.pack == pack) : (!it.pack));
|
||||
}
|
||||
|
||||
findRefItem(ref) {
|
||||
return this.system.items.find(RdDItemService.matchRefItem(ref));
|
||||
}
|
||||
|
||||
async increaseRefItemQuantite(ref, quantite) {
|
||||
await this.updateRefItem(ref,
|
||||
it => it.system.quantite = Math.max(0, it.system.quantite + quantite)
|
||||
);
|
||||
}
|
||||
|
||||
async updateRefItem(ref, update = it => { }) {
|
||||
await this.updateRefItems(RdDItemService.matchRefItem(ref), update);
|
||||
}
|
||||
|
||||
async addRefItem(newItem) {
|
||||
if (!newItem.id) {
|
||||
ui.notifications.warn(`${newItem?.name ?? '??'} n'a pas d'identifiant`);
|
||||
return;
|
||||
}
|
||||
if (this.system.items.find(RdDItemService.matchRefItem(newItem))) {
|
||||
ui.notifications.warn(`${newItem?.name ?? newItem.id} est déjà présent ici`);
|
||||
return;
|
||||
}
|
||||
await this.setRefItems([...this.system.items, newItem]);
|
||||
}
|
||||
|
||||
async removeRefItem(ref) {
|
||||
await this.removeRefItems(RdDItemService.matchRefItem(ref));
|
||||
}
|
||||
|
||||
async removeRefItems(matcher = it => false) {
|
||||
await this.setRefItems(this.system.items.filter(it => !matcher(it)));
|
||||
}
|
||||
|
||||
async updateRefItems(matcher = it => false, update = it => { }) {
|
||||
const updatedList = this.system.items.map(it => {
|
||||
if (matcher(it)) {
|
||||
update(it);
|
||||
}
|
||||
return it;
|
||||
});
|
||||
await this.setRefItems(updatedList);
|
||||
}
|
||||
|
||||
async setRefItems(newItems) {
|
||||
await this.update({ 'system.items': newItems.sort(Misc.ascending(it => it.type + ':' + it.name)) });
|
||||
}
|
||||
|
||||
}
|
@ -4,59 +4,35 @@ import { RdDAlchimie } from "./rdd-alchimie.js";
|
||||
import { RdDItemCompetence } from "./item-competence.js";
|
||||
import { RdDHerbes } from "./rdd-herbes.js";
|
||||
import { RdDGemme } from "./rdd-gemme.js";
|
||||
import { Misc } from "./misc.js";
|
||||
import { HtmlUtility } from "./html-utility.js";
|
||||
import { ReglesOptionelles } from "./settings/regles-optionelles.js";
|
||||
import { ReglesOptionelles } from "./regles-optionelles.js";
|
||||
import { SYSTEM_RDD } from "./constants.js";
|
||||
import { RdDSheetUtility } from "./rdd-sheet-utility.js";
|
||||
import { SystemCompendiums } from "./settings/system-compendiums.js";
|
||||
import { Misc } from "./misc.js";
|
||||
|
||||
/**
|
||||
* Extend the basic ItemSheet for RdD specific items
|
||||
* Extend the basic ItemSheet with some very simple modifications
|
||||
* @extends {ItemSheet}
|
||||
*/
|
||||
export class RdDItemSheet extends ItemSheet {
|
||||
|
||||
static get ITEM_TYPE() {
|
||||
return undefined
|
||||
}
|
||||
|
||||
static defaultTemplate(type) {
|
||||
return type ?
|
||||
`systems/foundryvtt-reve-de-dragon/templates/item-${type}-sheet.html` :
|
||||
"systems/foundryvtt-reve-de-dragon/templates/item-sheet.html";
|
||||
}
|
||||
|
||||
static register(sheetClass) {
|
||||
Items.registerSheet(SYSTEM_RDD, sheetClass, {
|
||||
label: Misc.typeName('Item', sheetClass.ITEM_TYPE),
|
||||
types: [sheetClass.ITEM_TYPE],
|
||||
makeDefault: true
|
||||
})
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
classes: [SYSTEM_RDD, "sheet", "item"],
|
||||
template: RdDItemSheet.defaultTemplate(RdDItemSheet.ITEM_TYPE),
|
||||
template: "systems/foundryvtt-reve-de-dragon/templates/item-sheet.html",
|
||||
width: 550,
|
||||
height: 550
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
get template() {
|
||||
return RdDItemSheet.defaultTemplate(this.item.type);
|
||||
}
|
||||
|
||||
get title() {
|
||||
return `${Misc.typeName('Item', this.item.type)}: ${this.item.name}`;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_getHeaderButtons() {
|
||||
let buttons = super._getHeaderButtons();
|
||||
if (this.item.isInventaire() && this.item.isVideOuNonConteneur()) {
|
||||
// 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!
|
||||
if ("cout" in Misc.templateData(this.object) && this.object.isVideOuNonConteneur()) {
|
||||
buttons.unshift({
|
||||
class: "vendre",
|
||||
icon: "fas fa-comments-dollar",
|
||||
@ -84,200 +60,233 @@ export class RdDItemSheet extends ItemSheet {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async getData() {
|
||||
const objectData = Misc.data(this.object)
|
||||
let formData = {
|
||||
id: this.item.id,
|
||||
title: this.item.name,
|
||||
type: this.item.type,
|
||||
img: this.item.img,
|
||||
name: this.item.name,
|
||||
system: this.item.system,
|
||||
id: this.object.id,
|
||||
title: objectData.name,
|
||||
type: objectData.type,
|
||||
img: objectData.img,
|
||||
name: objectData.name,
|
||||
data: objectData.data,
|
||||
isGM: game.user.isGM,
|
||||
actorId: this.actor?.id,
|
||||
isOwned: this.actor ? true : false,
|
||||
owner: this.item.isOwner,
|
||||
owner: this.document.isOwner,
|
||||
editable: this.isEditable,
|
||||
cssClass: this.isEditable ? "editable" : "locked",
|
||||
isSoins: false,
|
||||
description: await TextEditor.enrichHTML(this.item.system.description, { async: true }),
|
||||
descriptionmj: await TextEditor.enrichHTML(this.item.system.descriptionmj, { async: true }),
|
||||
isComestible: this.item.isComestible()
|
||||
isSoins: false
|
||||
}
|
||||
if (this.actor) {
|
||||
formData.isOwned = true;
|
||||
if (objectData.type == 'conteneur') {
|
||||
this.prepareConteneurData(formData);
|
||||
}
|
||||
}
|
||||
|
||||
const competences = await SystemCompendiums.getCompetences(this.actor?.type);
|
||||
formData.categorieCompetences = RdDItemCompetence.getCategorieCompetences()
|
||||
if (this.item.type == 'tache' || this.item.type == 'livre' || this.item.type == 'meditation' || this.item.type == 'oeuvre') {
|
||||
if (formData.type == 'tache' || formData.type == 'livre' || formData.type == 'meditation' || formData.type == 'oeuvre') {
|
||||
formData.caracList = duplicate(game.system.model.Actor.personnage.carac)
|
||||
formData.caracList["reve-actuel"] = duplicate(game.system.model.Actor.personnage.reve.reve)
|
||||
formData.competences = competences;
|
||||
formData.competences = await RdDUtility.loadCompendium('foundryvtt-reve-de-dragon.competences')
|
||||
}
|
||||
if (this.item.type == 'arme') {
|
||||
formData.competences = competences.filter(it => RdDItemCompetence.isCompetenceArme(it));
|
||||
if (formData.type == 'arme') {
|
||||
formData.competences = await RdDUtility.loadCompendium('foundryvtt-reve-de-dragon.competences', it => RdDItemCompetence.isCompetenceArme(it));
|
||||
console.log(formData.competences)
|
||||
}
|
||||
if (['sort', 'sortreserve'].includes(this.item.type)) {
|
||||
formData.competences = competences.filter(it => RdDItemCompetence.isDraconic(it));
|
||||
if (formData.type == 'recettealchimique') {
|
||||
RdDAlchimie.processManipulation(objectData, this.actor && this.actor.id);
|
||||
}
|
||||
if (this.item.type == 'recettecuisine') {
|
||||
formData.ingredients = await TextEditor.enrichHTML(this.object.system.ingredients, { async: true })
|
||||
}
|
||||
if (this.item.type == 'extraitpoetique') {
|
||||
formData.extrait = await TextEditor.enrichHTML(this.object.system.extrait, { async: true })
|
||||
formData.texte = await TextEditor.enrichHTML(this.object.system.texte, { async: true })
|
||||
}
|
||||
if (this.item.type == 'recettealchimique') {
|
||||
RdDAlchimie.processManipulation(this.item, this.actor && this.actor.id);
|
||||
formData.manipulation_update = await TextEditor.enrichHTML(this.object.system.manipulation_update, { async: true })
|
||||
formData.utilisation = await TextEditor.enrichHTML(this.object.system.utilisation, { async: true })
|
||||
formData.enchantement = await TextEditor.enrichHTML(this.object.system.enchantement, { async: true })
|
||||
formData.sureffet = await TextEditor.enrichHTML(this.object.system.sureffet, { async: true })
|
||||
}
|
||||
if (this.item.type == 'gemme') {
|
||||
if (formData.type == 'gemme') {
|
||||
formData.gemmeTypeList = RdDGemme.getGemmeTypeOptionList();
|
||||
RdDGemme.calculDataDerivees(this.item);
|
||||
RdDGemme.calculDataDerivees(formData.data);
|
||||
}
|
||||
if (this.item.type == 'potion') {
|
||||
if (formData.type == 'potion') {
|
||||
if (this.dateUpdated) {
|
||||
formData.system.prdate = this.dateUpdated;
|
||||
formData.data.prdate = this.dateUpdated;
|
||||
this.dateUpdated = undefined;
|
||||
}
|
||||
await RdDHerbes.updatePotionData(formData);
|
||||
RdDHerbes.updatePotionData(formData);
|
||||
}
|
||||
if (formData.isOwned && this.item.type == 'herbe' && (formData.system.categorie == 'Soin' || formData.system.categorie == 'Repos')) {
|
||||
if (formData.isOwned && formData.type == 'herbe' && (formData.data.categorie == 'Soin' || formData.data.categorie == 'Repos')) {
|
||||
formData.isIngredientPotionBase = true;
|
||||
}
|
||||
if (this.item.type == 'sortreserve') {
|
||||
const sortId = this.item.system.sortid;
|
||||
formData.sort = formData.isOwned ? this.item.actor.items.get(sortId) : game.items.get(sortId);
|
||||
}
|
||||
formData.bonusCaseList = RdDItemSort.getBonusCaseList(formData, true);
|
||||
|
||||
return formData;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
prepareConteneurData(formData) {
|
||||
formData.itemsByType = Misc.classify(this.actor.items.map(i => foundry.utils.deepClone(i.data)));
|
||||
RdDUtility.filterEquipementParType(formData);
|
||||
|
||||
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.objets);
|
||||
formData.subItems = formData.conteneurs.find(it => it._id == this.object.id)?.subItems;
|
||||
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
this.html = html;
|
||||
|
||||
HtmlUtility._showControlWhen(this.html.find(".item-cout"), ReglesOptionelles.isUsing('afficher-prix-joueurs') || game.user.isGM || !this.item.isOwned);
|
||||
HtmlUtility._showControlWhen(this.html.find(".item-magique"), this.item.isMagique());
|
||||
if (this.object.type == 'conteneur') {
|
||||
this.form.ondragstart = (event) => this._onDragStart(event);
|
||||
this.form.ondrop = (event) => this._onDrop(event);
|
||||
}
|
||||
|
||||
let itemSheetDialog = this;
|
||||
|
||||
HtmlUtility._showControlWhen($(".item-cout"), ReglesOptionelles.isUsing('afficher-prix-joueurs') || game.user.isGM || !this.object.isOwned);
|
||||
HtmlUtility._showControlWhen($(".item-magique"), this.object.isMagique());
|
||||
|
||||
// Everything below here is only needed if the sheet is editable
|
||||
if (!this.options.editable) return;
|
||||
|
||||
this.form.ondragstart = (event) => this._onDragStart(event);
|
||||
this.form.ondrop = (event) => this._onDrop(event);
|
||||
|
||||
// Select competence categorie
|
||||
this.html.find(".categorie").change(event => this._onSelectCategorie(event));
|
||||
html.find(".categorie").change(event => this._onSelectCategorie(event));
|
||||
|
||||
this.html.find('.sheet-competence-xp').change((event) => {
|
||||
if (this.item.isCompetencePersonnage()) {
|
||||
RdDUtility.checkThanatosXP(this.item.name);
|
||||
html.find('.sheet-competence-xp').change((event) => {
|
||||
if (this.object.data.type == 'competence') {
|
||||
RdDUtility.checkThanatosXP(this.object.data.name);
|
||||
}
|
||||
});
|
||||
this.html.find(".item-cout input[name='system.cout']").change(event => {
|
||||
if (this.item.isMonnaie()) {
|
||||
const value = event.currentTarget.value;
|
||||
if (Number(value) == 0) {
|
||||
ui.notifications.error(`${this.actor?.name ?? 'Monnaie'}: La monnaie ${this.item.name} a maintenant une valeur de 0, et ne peut plus être utilisée pour payer!`)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
this.html.find('.enchanteDate').change((event) => {
|
||||
let jour = Number(this.html.find('[name="splitDate.day"]').val());
|
||||
let mois = this.html.find('[name="splitDate.month"]').val();
|
||||
html.find('.enchanteDate').change((event) => {
|
||||
let jour = Number($('#jourMois').val());
|
||||
let mois = $('#nomMois').val();
|
||||
this.dateUpdated = game.system.rdd.calendrier.getIndexFromDate(jour, mois);
|
||||
});
|
||||
|
||||
this.html.find('.creer-tache-livre').click((event) => this._getEventActor(event).creerTacheDepuisLivre(this.item));
|
||||
this.html.find('.consommer-potion').click((event) => this._getEventActor(event).consommerPotion(this.item));
|
||||
this.html.find('.creer-potion-base').click((event) => this._getEventActor(event).dialogFabriquerPotion(this.item));
|
||||
html.find('.creer-tache-livre').click((event) => {
|
||||
let actorId = event.currentTarget.attributes['data-actor-id'].value;
|
||||
let actor = game.actors.get(actorId);
|
||||
actor.creerTacheDepuisLivre(this.item);
|
||||
});
|
||||
html.find('.consommer-potion').click((event) => {
|
||||
let actorId = event.currentTarget.attributes['data-actor-id'].value;
|
||||
let actor = game.actors.get(actorId);
|
||||
actor.consommerPotion(this.item);
|
||||
});
|
||||
html.find('.creer-potion-base').click((event) => {
|
||||
let actorId = event.currentTarget.attributes['data-actor-id'].value;
|
||||
let actor = game.actors.get(actorId);
|
||||
actor.dialogFabriquerPotion(this.item);
|
||||
});
|
||||
|
||||
this.html.find('.alchimie-tache a').click((event) => {
|
||||
let actor = this._getEventActor(event);
|
||||
html.find('.alchimie-tache a').click((event) => {
|
||||
let actorId = event.currentTarget.attributes['data-actor-id'].value;
|
||||
let recetteId = event.currentTarget.attributes['data-recette-id'].value;
|
||||
let tacheName = event.currentTarget.attributes['data-alchimie-tache'].value;
|
||||
let tacheData = event.currentTarget.attributes['data-alchimie-data'].value;
|
||||
let actor = game.actors.get(actorId);
|
||||
if (actor) {
|
||||
let recetteId = event.currentTarget.attributes['data-recette-id'].value;
|
||||
let tacheName = event.currentTarget.attributes['data-alchimie-tache'].value;
|
||||
let tacheData = event.currentTarget.attributes['data-alchimie-data'].value;
|
||||
actor.effectuerTacheAlchimie(recetteId, tacheName, tacheData);
|
||||
} else {
|
||||
ui.notifications.info("Impossible trouver un acteur pour réaliser cette tache Alchimique.");
|
||||
ui.notifications.info("Impossible trouver un actur pour réaliser cette tache Alchimique.");
|
||||
}
|
||||
});
|
||||
|
||||
this.html.find('.item-split').click(async event => RdDSheetUtility.splitItem(RdDSheetUtility.getItem(event, this.actor), this.actor, async () => this.render(true)));
|
||||
this.html.find('.item-edit').click(async event => RdDSheetUtility.getItem(event, this.actor)?.sheet.render(true));
|
||||
this.html.find('.item-delete').click(async event => RdDUtility.confirmActorItemDelete(this, RdDSheetUtility.getItem(event, this.actor)));
|
||||
this.html.find('.item-vendre').click(async event => RdDSheetUtility.getItem(event, this.actor)?.proposerVente());
|
||||
this.html.find('.item-montrer').click(async event => RdDSheetUtility.getItem(event, this.actor)?.postItem());
|
||||
this.html.find('.item-action').click(async event => RdDSheetUtility.getItem(event, this.actor)?.actionPrincipale(this.actor, async () => this.render(true)));
|
||||
}
|
||||
|
||||
_getEventActor(event) {
|
||||
let actorId = event.currentTarget.attributes['data-actor-id'].value;
|
||||
let actor = game.actors.get(actorId);
|
||||
return actor;
|
||||
html.find('.item-split').click(async event => {
|
||||
const item = RdDSheetUtility.getItem(event, this.actor);
|
||||
await RdDSheetUtility.splitItem(item, this.actor, async () => itemSheetDialog.render(true));
|
||||
});
|
||||
html.find('.item-edit').click(async event => {
|
||||
const item = RdDSheetUtility.getItem(event, this.actor);
|
||||
item.sheet.render(true);
|
||||
});
|
||||
html.find('.item-delete').click(async event => {
|
||||
const li = RdDSheetUtility.getEventElement(event);
|
||||
RdDUtility.confirmerSuppression(this, li);
|
||||
});
|
||||
html.find('.item-vendre').click(async event => {
|
||||
const item = RdDSheetUtility.getItem(event, this.actor);
|
||||
item?.proposerVente();
|
||||
});
|
||||
html.find('.item-montrer').click(async event => {
|
||||
const item = RdDSheetUtility.getItem(event, this.actor);
|
||||
item?.postItem();
|
||||
});
|
||||
html.find('.item-action').click(async event => {
|
||||
const item = RdDSheetUtility.getItem(event, this.actor);
|
||||
this.actor.actionItem(item, async () => itemSheetDialog.render(true));
|
||||
});
|
||||
html.find('.conteneur-name a').click(async event => {
|
||||
RdDUtility.toggleAfficheContenu(RdDSheetUtility.getItemId(event));
|
||||
this.render(true);
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async _onSelectCategorie(event) {
|
||||
event.preventDefault();
|
||||
|
||||
if (this.item.isCompetence()) {
|
||||
if (this.object.isCompetence()) {
|
||||
let level = RdDItemCompetence.getNiveauBase(event.currentTarget.value);
|
||||
this.item.system.base = level;
|
||||
this.html.find('[name="system.base"]').val(level);
|
||||
Misc.templateData(this.object).base = level;
|
||||
$("#base").val(level);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
get template() {
|
||||
let type = this.object.data.type;
|
||||
return `systems/foundryvtt-reve-de-dragon/templates/item-${type}-sheet.html`;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
_updateObject(event, formData) {
|
||||
if (this.item.type == 'sort') {
|
||||
// Données de bonus de cases ?
|
||||
formData['system.bonuscase'] = RdDItemSort.buildBonusCaseStringFromFormData(formData.bonusValue, formData.caseValue);
|
||||
}
|
||||
_updateObject(event, formData) { // Deprecated en v0.8 à clarifier
|
||||
// Données de bonus de cases ?
|
||||
formData = RdDItemSort.buildBonusCaseStringFromFormData(formData);
|
||||
|
||||
return this.item.update(formData);
|
||||
return this.object.update(formData);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async _onDragStart(event) {
|
||||
console.log("_onDragStart", event);
|
||||
if (event.target.classList.contains("entity-link")) return;
|
||||
|
||||
const itemId = event.srcElement?.attributes["data-item-id"].value;
|
||||
const item = this.actor.items.get(itemId);
|
||||
// Create drag data
|
||||
const dragData = {
|
||||
actorId: this.actor.id,
|
||||
type: "Item",
|
||||
data: item.data
|
||||
};
|
||||
|
||||
event.dataTransfer.setData("text/plain", JSON.stringify(dragData));
|
||||
}
|
||||
|
||||
async _onDrop(event) {
|
||||
// Try to extract the dragData
|
||||
let dragData = RdDItemSheet.$extractDragData(event);
|
||||
if (!dragData) return false;
|
||||
const allowed = Hooks.call("dropActorSheetData", this.actor, this, dragData);
|
||||
if (allowed === false) return false;
|
||||
// Try to extract the data
|
||||
let data;
|
||||
try {
|
||||
data = JSON.parse(event.dataTransfer.getData('text/plain'));
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle different dragData types
|
||||
switch (dragData.type) {
|
||||
const allowed = Hooks.call("dropActorSheetData", this.actor, this, data);
|
||||
if (allowed === false) return;
|
||||
|
||||
// Handle different data types
|
||||
switch (data.type) {
|
||||
case "Item":
|
||||
return this._onDropItem(event, dragData);
|
||||
case "Actor":
|
||||
return this._onDropActor(event, dragData);
|
||||
return this._onDropItem(event, data);
|
||||
}
|
||||
return super._onDrop(event);
|
||||
}
|
||||
|
||||
static $extractDragData(event) {
|
||||
try {
|
||||
const eventData = event?.dataTransfer?.getData('text/plain');
|
||||
if (eventData) {
|
||||
return JSON.parse(eventData);
|
||||
}
|
||||
} catch (err) { }
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async _onDropItem(event, dragData) {
|
||||
if (this.actor) {
|
||||
const dropParams = RdDSheetUtility.prepareItemDropParameters(this.object.id, this.actor.id, dragData, this.objetVersConteneur);
|
||||
await this.actor.processDropItem(dropParams);
|
||||
await this.render(true);
|
||||
}
|
||||
}
|
||||
|
||||
async _onDropActor(event, dragData) {
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,14 +1,30 @@
|
||||
import { RdDItemSheet } from "./item-sheet.js";
|
||||
import { SYSTEM_RDD } from "./constants.js";
|
||||
import { RdDItemSigneDraconique } from "./item-signedraconique.js";
|
||||
import { TMRUtility } from "./tmr-utility.js";
|
||||
import { Misc } from "./misc.js";
|
||||
import { TMRType, TMRUtility } from "./tmr-utility.js";
|
||||
|
||||
/**
|
||||
* Item sheet pour signes draconiques
|
||||
* @extends {RdDItemSheet}
|
||||
* @extends {ItemSheet}
|
||||
*/
|
||||
export class RdDSigneDraconiqueItemSheet extends RdDItemSheet {
|
||||
export class RdDSigneDraconiqueItemSheet extends ItemSheet {
|
||||
|
||||
static get ITEM_TYPE() { return "signedraconique" }
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
classes: [SYSTEM_RDD, "sheet", "item"],
|
||||
template: "systems/foundryvtt-reve-de-dragon/templates/item-signedraconique-sheet.html",
|
||||
width: 550,
|
||||
height: 550
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_getHeaderButtons() {
|
||||
let buttons = super._getHeaderButtons();
|
||||
buttons.unshift({ class: "post", icon: "fas fa-comment", onclick: ev => this.item.postItem() });
|
||||
return buttons;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
@ -16,16 +32,25 @@ export class RdDSigneDraconiqueItemSheet extends RdDItemSheet {
|
||||
const position = super.setPosition(options);
|
||||
const sheetHeader = this.element.find(".sheet-header");
|
||||
const sheetBody = this.element.find(".sheet-body");
|
||||
sheetBody.css("height", position.height - sheetHeader[0].clientHeight)
|
||||
const bodyHeight = position.height - sheetHeader[0].clientHeight;
|
||||
sheetBody.css("height", bodyHeight);
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async getData() {
|
||||
const formData = await super.getData();
|
||||
this.tmrs = TMRUtility.buildSelectionTypesTMR(this.item.system.typesTMR);
|
||||
formData.tmrs = this.tmrs;
|
||||
const formData = duplicate(Misc.data(this.object));
|
||||
mergeObject(formData, {
|
||||
title: formData.name,
|
||||
isGM: game.user.isGM,
|
||||
owner: this.document.isOwner,
|
||||
isOwned: this.actor ? true : false,
|
||||
actorId: this.actor?.id,
|
||||
editable: this.isEditable,
|
||||
cssClass: this.isEditable ? "editable" : "locked",
|
||||
});
|
||||
formData.tmrs = TMRUtility.listSelectedTMR(formData.data.typesTMR ?? []);
|
||||
return formData;
|
||||
}
|
||||
|
||||
@ -37,32 +62,35 @@ export class RdDSigneDraconiqueItemSheet extends RdDItemSheet {
|
||||
if (!this.options.editable) return;
|
||||
|
||||
html.find(".signe-aleatoire").click(event => this.setSigneAleatoire());
|
||||
html.find("input.select-tmr").change(event => this.onSelectTmr(event));
|
||||
html.find(".signe-xp-sort").change(event => this.onValeurXpSort(event.currentTarget.attributes['data-typereussite']?.value, Number(event.currentTarget.value)));
|
||||
html.find(".select-tmr").change((event) => this.onSelectTmr(event));
|
||||
html.find(".signe-xp-sort").change((event) => this.onValeurXpSort(event.currentTarget.attributes['data-typereussite']?.value, Number(event.currentTarget.value)));
|
||||
}
|
||||
|
||||
async setSigneAleatoire() {
|
||||
const newSigne = await RdDItemSigneDraconique.randomSigneDraconique();
|
||||
newSigne.name = this.item.name;
|
||||
this.item.update(newSigne);
|
||||
this.object.update(newSigne);
|
||||
}
|
||||
|
||||
async onSelectTmr(event) {
|
||||
const tmrName = $(event.currentTarget)?.data("tmr-name");
|
||||
const onTmr = this.tmrs.find(it => it.name == tmrName);
|
||||
if (onTmr){
|
||||
onTmr.selected = event.currentTarget.checked;
|
||||
}
|
||||
|
||||
this.item.update({ 'system.typesTMR': TMRUtility.buildListTypesTMRSelection(this.tmrs) });
|
||||
event.preventDefault();
|
||||
const selectedTMR = $(".select-tmr").val();
|
||||
this.object.update({ 'data.typesTMR': selectedTMR });
|
||||
}
|
||||
|
||||
async onValeurXpSort(event) {
|
||||
const codeReussite = event.currentTarget.attributes['data-typereussite']?.value ?? 0;
|
||||
const xp = Number(event.currentTarget.value);
|
||||
const oldValeur = this.item.system.valeur;
|
||||
const oldValeur = Misc.templateData(this.object).valeur;
|
||||
const newValeur = RdDItemSigneDraconique.calculValeursXpSort(codeReussite, xp, oldValeur);
|
||||
await this.item.update({ 'system.valeur': newValeur });
|
||||
await this.object.update({ 'data.valeur': newValeur });
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
get template() {
|
||||
return `systems/foundryvtt-reve-de-dragon/templates/item-signedraconique-sheet.html`;
|
||||
}
|
||||
|
||||
get title() {
|
||||
return `Signe draconique: ${this.object.name}`;
|
||||
}
|
||||
}
|
||||
|
@ -18,12 +18,13 @@ const DIFFICULTE_LECTURE_SIGNE_MANQUE = +11;
|
||||
export class RdDItemSigneDraconique {
|
||||
|
||||
static prepareSigneDraconiqueMeditation(meditation, rolled) {
|
||||
meditation = Misc.data(meditation);
|
||||
return {
|
||||
name: "de la " + meditation.name,
|
||||
type: "signedraconique",
|
||||
img: meditation.img,
|
||||
system: {
|
||||
typesTMR: [TMRUtility.typeTmrName(meditation.system.tmr)],
|
||||
data: {
|
||||
typesTMR: [TMRUtility.typeTmrName(meditation.data.tmr)],
|
||||
difficulte: rolled.isSuccess ? RdDItemSigneDraconique.getDiffSigneMeditation(rolled.code) : DIFFICULTE_LECTURE_SIGNE_MANQUE,
|
||||
ephemere: true,
|
||||
duree: "1 round",
|
||||
@ -42,7 +43,7 @@ export class RdDItemSigneDraconique {
|
||||
}
|
||||
|
||||
static getXpSortSigneDraconique(code, signe) {
|
||||
return Misc.toInt(signe.system.valeur[code] ?? 0);
|
||||
return Misc.toInt(Misc.data(signe).data.valeur[code] ?? 0);
|
||||
}
|
||||
|
||||
static calculValeursXpSort(qualite, valeur, avant) {
|
||||
@ -74,7 +75,7 @@ export class RdDItemSigneDraconique {
|
||||
name: await RdDItemSigneDraconique.randomSigneDescription(),
|
||||
type: "signedraconique",
|
||||
img: defaultItemImg.signedraconique,
|
||||
system: {
|
||||
data: {
|
||||
typesTMR: await RdDItemSigneDraconique.randomTmrs(modele.nbCases),
|
||||
ephemere: options?.ephemere == undefined ? RdDDice.rollTotal("1d2") == 2 : options.ephemere,
|
||||
duree: "1 round",
|
||||
|
@ -7,25 +7,25 @@ export class RdDItemSort extends Item {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isDifficulteVariable(sort) {
|
||||
return sort && (sort.system.difficulte.toLowerCase() == "variable");
|
||||
return sort && (sort.data.difficulte.toLowerCase() == "variable");
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isCoutVariable(sort) {
|
||||
return sort && (sort.system.ptreve.toLowerCase() == "variable" || sort.system.ptreve.indexOf("+") >= 0);
|
||||
return sort && (sort.data.ptreve.toLowerCase() == "variable" || sort.data.ptreve.indexOf("+") >= 0);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static setCoutReveReel(sort){
|
||||
if (sort) {
|
||||
sort.system.ptreve_reel = this.isCoutVariable(sort) ? 1 : sort.system.ptreve;
|
||||
sort.data.ptreve_reel = this.isCoutVariable(sort) ? 1 : sort.data.ptreve;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getDifficulte(sort, variable) {
|
||||
if (sort && !RdDItemSort.isDifficulteVariable(sort)) {
|
||||
return Misc.toInt(sort.system.difficulte);
|
||||
return Misc.toInt(sort.data.difficulte);
|
||||
}
|
||||
return variable;
|
||||
}
|
||||
@ -54,35 +54,40 @@ export class RdDItemSort extends Item {
|
||||
static getBonusCaseList( item, newCase = false ) {
|
||||
// Gestion spéciale case bonus
|
||||
if ( item.type == 'sort') {
|
||||
return this.buildBonusCaseList(item.system.bonuscase, newCase );
|
||||
return this.buildBonusCaseList(item.data.bonuscase, newCase );
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** Met à jour les données de formulaire
|
||||
* si static des bonus de cases sont présents
|
||||
* */
|
||||
static buildBonusCaseStringFromFormData( bonuses, cases ) {
|
||||
if ( bonuses ) {
|
||||
let list = [];
|
||||
let caseCheck = {};
|
||||
for (let i=0; i<bonuses.length; i++) {
|
||||
let coord = cases[i]?.toUpperCase() || 'A1';
|
||||
let bonus = bonuses[i] || 0;
|
||||
if ( TMRUtility.verifyTMRCoord( coord ) && bonus > 0 && caseCheck[coord] == undefined ) {
|
||||
caseCheck[coord] = bonus;
|
||||
list.push( coord+":"+bonus );
|
||||
/* -------------------------------------------- */
|
||||
/** Met à jour les données de formulaire
|
||||
* si static des bonus de cases sont présents
|
||||
* */
|
||||
static buildBonusCaseStringFromFormData( formData ) {
|
||||
if ( formData.bonusValue ) {
|
||||
let list = [];
|
||||
let caseCheck = {};
|
||||
for(let i=0; i<formData.bonusValue.length; i++) {
|
||||
let coord = formData.caseValue[i] || 'A1';
|
||||
coord = coord.toUpperCase();
|
||||
if ( TMRUtility.verifyTMRCoord( coord ) ) { // Sanity check
|
||||
let bonus = formData.bonusValue[i] || 0;
|
||||
if ( bonus > 0 && caseCheck[coord] == undefined ) {
|
||||
caseCheck[coord] = bonus;
|
||||
list.push( coord+":"+bonus );
|
||||
}
|
||||
}
|
||||
}
|
||||
formData.bonusValue = undefined;
|
||||
formData.caseValue = undefined;
|
||||
formData['data.bonuscase'] = list.toString(); // Reset
|
||||
}
|
||||
return list.toString();
|
||||
}
|
||||
return undefined;
|
||||
return formData;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static incrementBonusCase( actor, sort, coord ) {
|
||||
let bonusCaseList = this.buildBonusCaseList(sort.system.bonuscase, false);
|
||||
let bonusCaseList = this.buildBonusCaseList(sort.data.bonuscase, false);
|
||||
//console.log("ITEMSORT", sort, bonusCaseList);
|
||||
|
||||
let found = false;
|
||||
@ -101,12 +106,12 @@ export class RdDItemSort extends Item {
|
||||
// Sauvegarde/update
|
||||
let bonuscase = StringList.toString();
|
||||
//console.log("Bonus cae :", bonuscase);
|
||||
actor.updateEmbeddedDocuments('Item', [{ _id: sort._id, 'system.bonuscase': bonuscase }] );
|
||||
actor.updateEmbeddedDocuments('Item', [{ _id: sort._id, 'data.bonuscase': bonuscase }] );
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getCaseBonus( sort, coord) {
|
||||
let bonusCaseList = this.buildBonusCaseList(sort.system.bonuscase, false);
|
||||
let bonusCaseList = this.buildBonusCaseList(sort.data.bonuscase, false);
|
||||
for( let bc of bonusCaseList) {
|
||||
if (bc.case == coord) { // Case existante
|
||||
return Number(bc.bonus);
|
||||
|
765
module/item.js
@ -1,393 +0,0 @@
|
||||
import { LOG_HEAD, SYSTEM_RDD } from "./constants.js";
|
||||
import { Environnement } from "./environnement.js";
|
||||
import { Grammar } from "./grammar.js";
|
||||
|
||||
class Migration {
|
||||
get code() { return "sample"; }
|
||||
get version() { return "0.0.0"; }
|
||||
async migrate() { }
|
||||
|
||||
async applyItemsUpdates(computeUpdates) {
|
||||
await game.actors.forEach(async (actor) => {
|
||||
const actorItemUpdates = computeUpdates(actor.items);
|
||||
if (actorItemUpdates.length > 0) {
|
||||
console.log(
|
||||
this.code,
|
||||
`Applying updates on actor ${actor.name} items`,
|
||||
actorItemUpdates
|
||||
);
|
||||
await actor.updateEmbeddedDocuments("Item", actorItemUpdates);
|
||||
}
|
||||
});
|
||||
|
||||
const itemUpdates = computeUpdates(game.items);
|
||||
if (itemUpdates.length > 0) {
|
||||
console.log(this.code, "Applying updates on items", itemUpdates);
|
||||
await Item.updateDocuments(itemUpdates);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class _1_5_34_migrationPngWebp {
|
||||
get code() { return "migrationPngWebp"; }
|
||||
get version() { return "1.5.34"; }
|
||||
async migrate() {
|
||||
|
||||
const regexOldPngJpg = /(systems\/foundryvtt-reve-de-dragon\/icons\/.*)\.(png|jpg)/;
|
||||
const replaceWithWebp = '$1.webp';
|
||||
function convertImgToWebp(img) {
|
||||
return img.replace(regexOldPngJpg, replaceWithWebp);
|
||||
}
|
||||
function prepareDocumentsImgUpdate(documents) {
|
||||
return documents.filter(it => it.img && it.img.match(regexOldPngJpg))
|
||||
.map(it => {
|
||||
return { _id: it.id, img: convertImgToWebp(it.img) }
|
||||
});
|
||||
}
|
||||
|
||||
const itemsUpdates = prepareDocumentsImgUpdate(game.items);
|
||||
const actorsUpdates = prepareDocumentsImgUpdate(game.actors);
|
||||
//Migrate system png to webp
|
||||
await Item.updateDocuments(itemsUpdates);
|
||||
await Actor.updateDocuments(actorsUpdates);
|
||||
game.actors.forEach(actor => {
|
||||
if (actor.token?.img && actor.token.img.match(regexOldPngJpg)) {
|
||||
actor.update({ "token.img": convertImgToWebp(actor.token.img) });
|
||||
}
|
||||
const actorItemsToUpdate = prepareDocumentsImgUpdate(actor.items);
|
||||
actor.updateEmbeddedDocuments('Item', actorItemsToUpdate);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class _10_0_16_MigrationSortsReserve extends Migration {
|
||||
get code() { return "creation-item-sort-reserve"; }
|
||||
get version() { return "10.0.16"; }
|
||||
|
||||
async migrate() {
|
||||
await game.actors
|
||||
.filter((actor) => actor.type == "personnage")
|
||||
.filter((actor) => actor.system.reve?.reserve?.list?.length ?? 0 > 0)
|
||||
.forEach(async (actor) => {
|
||||
const sortsReserve = actor.system.reve.reserve.list.map(this.conversionSortReserve);
|
||||
console.log(`${LOG_HEAD} Migration des sorts en réserve de ${actor.name}`, sortsReserve);
|
||||
await actor.createEmbeddedDocuments("Item", sortsReserve, {
|
||||
renderSheet: false,
|
||||
});
|
||||
await actor.update({ 'system.reve.reserve': undefined })
|
||||
});
|
||||
}
|
||||
|
||||
conversionSortReserve(it) {
|
||||
return {
|
||||
type: 'sortreserve',
|
||||
name: it.sort.name,
|
||||
img: it.sort.img,
|
||||
system: {
|
||||
// ATTENTION, utilisation de data / _id possibles, encore présents pour les anciens sorts en réserve
|
||||
sortid: it.sort._id,
|
||||
draconic: it.sort.draconic,
|
||||
ptreve: (it.sort.system ?? it.sort.data).ptreve_reel,
|
||||
coord: it.coord,
|
||||
heurecible: 'Vaisseau',
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class _10_0_17_MigrationCompetenceCreature extends Migration {
|
||||
get code() { return "competences-creature-parade"; }
|
||||
get version() { return "10.0.17"; }
|
||||
|
||||
async migrate() {
|
||||
await this.applyItemsUpdates(items => items
|
||||
.filter(it => it.type == "competencecreature" && it.system.isparade && it.system.categorie_parade == "")
|
||||
.map(it => { return { _id: it.id, "system.categorie_parade": "armes-naturelles" } }));
|
||||
|
||||
await this.applyItemsUpdates(items => items
|
||||
.filter(it => it.type == "competencecreature" && it.system.iscombat)
|
||||
.map(it => { return { _id: it.id, "system.categorie": (Grammar.includesLowerCaseNoAccent(it.name, "lancee") ? "lancer" : "melee") } })
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class _10_0_21_VehiculeStructureResistanceMax extends Migration {
|
||||
get code() { return "vehicule-structure-resistance-max"; }
|
||||
get version() { return "10.0.21"; }
|
||||
|
||||
async migrate() {
|
||||
await game.actors
|
||||
.filter((actor) => actor.type == "vehicule")
|
||||
.forEach(async (actor) => {
|
||||
await actor.update({
|
||||
'system.etat.resistance.value': actor.system.resistance,
|
||||
'system.etat.resistance.max': actor.system.resistance,
|
||||
'system.etat.structure.value': actor.system.structure,
|
||||
'system.etat.structure.max': actor.system.structure
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class _10_0_33_MigrationNomsDraconic extends Migration {
|
||||
get code() { return "competences-creature-parade"; }
|
||||
get version() { return "10.0.33"; }
|
||||
|
||||
migrationNomDraconic(ancien) {
|
||||
if (typeof ancien == 'string') {
|
||||
switch (ancien) {
|
||||
case 'oniros': case "Voie d'Oniros": return "Voie d'Oniros";
|
||||
case 'hypnos': case "Voie d'Hypnos": return "Voie d'Hypnos";
|
||||
case 'narcos': case "Voie de Narcos": return "Voie de Narcos";
|
||||
case 'thanatos': case "Voie de Thanatos": return "Voie de Thanatos";
|
||||
}
|
||||
return ancien;
|
||||
}
|
||||
else if (typeof ancien.name == 'string') {
|
||||
return this.migrationNomDraconic(ancien.name)
|
||||
}
|
||||
return ancien;
|
||||
}
|
||||
async migrate() {
|
||||
|
||||
await this.applyItemsUpdates(items => items
|
||||
.filter(it => ["sort", "sortreserve"].includes(it.type)
|
||||
&& (typeof it.system.draconic == 'string') || (typeof it.system.draconic?.name == 'string'))
|
||||
.map(it => { return { _id: it.id, "system.draconic": this.migrationNomDraconic(it.system.draconic) } }));
|
||||
}
|
||||
}
|
||||
|
||||
class _10_2_5_ArmesTirLancer extends Migration {
|
||||
constructor() {
|
||||
super();
|
||||
this.dagues = { "system.competence": 'Dague', "system.lancer": 'Dague de jet', "system.portee_courte": 3, "system.portee_moyenne": 8, "system.portee_extreme": 15 }
|
||||
this.javelot = { "system.competence": 'Lance', "system.lancer": 'Javelot', "system.portee_courte": 6, "system.portee_moyenne": 12, "system.portee_extreme": 20 }
|
||||
this.fouet = { "system.competence": '', "system.lancer": 'Fouet', "system.portee_courte": 2, "system.portee_moyenne": 2, "system.portee_extreme": 3, "system.penetration": -1 }
|
||||
this.arc = { "system.competence": '', "system.tir": 'Arc' }
|
||||
this.arbalete = { "system.competence": '', "system.tir": 'Arbalète' }
|
||||
this.fronde = { "system.competence": '', "system.tir": 'Fronde' }
|
||||
|
||||
this.mappings = {
|
||||
'dague': { filter: it => true, updates: this.dagues },
|
||||
'dague de jet': { filter: it => true, updates: this.dagues },
|
||||
'javelot': { filter: it => true, updates: this.javelot },
|
||||
'lance': { filter: it => it.name == 'Javeline', updates: this.javelot },
|
||||
'fouet': { filter: it => true, updates: this.fouet },
|
||||
'arc': { filter: it => true, updates: this.arc },
|
||||
'arbalete': { filter: it => true, updates: this.arbalete },
|
||||
'fronde': { filter: it => true, updates: this.fronde },
|
||||
}
|
||||
}
|
||||
|
||||
get code() { return "separation-competences-tir-lancer"; }
|
||||
get version() { return "10.2.5"; }
|
||||
|
||||
migrateArmeTirLancer(it) {
|
||||
let updates = mergeObject({ _id: it.id }, this.getMapping(it).updates);
|
||||
console.log(it.name, updates);
|
||||
return updates;
|
||||
}
|
||||
|
||||
async migrate() {
|
||||
await this.applyItemsUpdates(items => items
|
||||
.filter(it => "arme" == it.type)
|
||||
.filter(it => this.isTirLancer(it))
|
||||
.filter(it => this.getMapping(it).filter(it))
|
||||
.map(it => this.migrateArmeTirLancer(it)));
|
||||
}
|
||||
|
||||
|
||||
isTirLancer(it) {
|
||||
return Object.keys(this.mappings).includes(this.getCompKey(it));
|
||||
}
|
||||
|
||||
getMapping(it) {
|
||||
return this.mappings[this.getCompKey(it)];
|
||||
}
|
||||
|
||||
getCompKey(it) {
|
||||
return Grammar.toLowerCaseNoAccent(it.system.competence);
|
||||
}
|
||||
}
|
||||
|
||||
class _10_2_10_DesirLancinant_IdeeFixe extends Migration {
|
||||
get code() { return "desir-lancinat-idee-fixe"; }
|
||||
get version() { return "10.2.10"; }
|
||||
|
||||
migrateQueue(it) {
|
||||
let categorie = undefined
|
||||
let name = it.name
|
||||
if (Grammar.toLowerCaseNoAccent(name).includes('desir')) {
|
||||
categorie = 'lancinant';
|
||||
name = it.name.replace('Désir lancinant : ', '');
|
||||
|
||||
}
|
||||
if (Grammar.toLowerCaseNoAccent(name).includes('idee fixe')) {
|
||||
categorie = 'ideefixe';
|
||||
name = it.name.replace('Idée fixe : ', '')
|
||||
}
|
||||
return {
|
||||
_id: it.id, name: name,
|
||||
'system.ideefixe': undefined,
|
||||
'system.lancinant': undefined,
|
||||
'system.categorie': categorie
|
||||
}
|
||||
}
|
||||
|
||||
async migrate() {
|
||||
await this.applyItemsUpdates(items => items
|
||||
.filter(it => ['queue', 'ombre'].includes(it.type))
|
||||
.map(it => this.migrateQueue(it))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _10_3_0_Inventaire extends Migration {
|
||||
get code() { return "migration-equipement-inventaire"; }
|
||||
get version() { return "10.3.0"; }
|
||||
|
||||
async migrate() {
|
||||
await this.applyItemsUpdates(items => {
|
||||
return this._updatesMonnaies(items)
|
||||
.concat(this._updatesNonEquipe(items))
|
||||
.concat(this._updatesObjets(items))
|
||||
});
|
||||
}
|
||||
|
||||
_updatesNonEquipe(items) {
|
||||
return items
|
||||
.filter(it => ['munition'].includes(it.type))
|
||||
.map(it => { return { _id: it.id, 'system.equipe': undefined } });
|
||||
}
|
||||
_updatesObjets(items) {
|
||||
return items
|
||||
.filter(it => ['objet'].includes(it.type))
|
||||
.map(it => { return { _id: it.id, 'system.resistance': undefined, 'system.equipe': undefined } });
|
||||
}
|
||||
_updatesMonnaies(items) {
|
||||
return items
|
||||
.filter(it => ['monnaie'].includes(it.type) && it.system.valeur_deniers != undefined)
|
||||
.map(it => { return { _id: it.id, 'system.cout': it.system.valeur_deniers / 100, 'system.valeur_deniers': undefined } });
|
||||
}
|
||||
}
|
||||
|
||||
class _10_3_0_FrequenceEnvironnement extends Migration {
|
||||
get code() { return "migration-frequence-resources"; }
|
||||
get version() { return "10.3.0"; }
|
||||
|
||||
async migrate() {
|
||||
await this.applyItemsUpdates(items => items.filter(it => ['herbe', 'ingredient'].includes(it.type))
|
||||
.map(it => this._updatesFrequences(it)));
|
||||
}
|
||||
|
||||
_updatesFrequences(it) {
|
||||
return {
|
||||
_id: it.id,
|
||||
'system.rarete': undefined,
|
||||
'system.environnement': [{ milieu: it.system.milieu, rarete: it.system.rarete, frequence: Environnement.getFrequenceRarete(it.system.rarete, 'frequence') }]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _10_3_17_Monnaies extends Migration {
|
||||
constructor() {
|
||||
super();
|
||||
this.mapValeur = {
|
||||
"Etain (1 denier)": { name: 'Denier (étain)', system: { cout: 0.01 } },
|
||||
"Bronze (10 deniers)": { name: "Sou (bronze)", system: { cout: 0.1 } },
|
||||
"Argent (1 sol)": { name: "Sol (argent)", system: { cout: 1 } },
|
||||
"Or (10 sols)": { name: "Dragon (or)", system: { cout: 10 } }
|
||||
};
|
||||
}
|
||||
get code() { return "migration-monnaies"; }
|
||||
get version() { return "10.3.17"; }
|
||||
|
||||
async migrate() {
|
||||
await this.applyItemsUpdates(items => this._updatesMonnaies(items));
|
||||
}
|
||||
|
||||
_updatesMonnaies(items) {
|
||||
return items
|
||||
.filter(it => 'monnaie' == it.type)
|
||||
.filter(it => this.mapValeur[it.name] != undefined)
|
||||
.map(it => {
|
||||
const correction = this.mapValeur[it.name];
|
||||
return {
|
||||
_id: it.id,
|
||||
'name': correction.name,
|
||||
'system.cout': correction.system.cout,
|
||||
'system.valeur_deniers': undefined
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class Migrations {
|
||||
static getMigrations() {
|
||||
return [
|
||||
new _1_5_34_migrationPngWebp(),
|
||||
new _10_0_16_MigrationSortsReserve(),
|
||||
new _10_0_17_MigrationCompetenceCreature(),
|
||||
new _10_0_21_VehiculeStructureResistanceMax(),
|
||||
new _10_0_33_MigrationNomsDraconic(),
|
||||
new _10_2_5_ArmesTirLancer(),
|
||||
new _10_2_10_DesirLancinant_IdeeFixe(),
|
||||
new _10_3_0_Inventaire(),
|
||||
new _10_3_0_FrequenceEnvironnement(),
|
||||
new _10_3_17_Monnaies()
|
||||
];
|
||||
}
|
||||
|
||||
constructor() {
|
||||
game.settings.register(SYSTEM_RDD, "systemMigrationVersion", {
|
||||
name: "System Migration Version",
|
||||
scope: "world",
|
||||
config: false,
|
||||
type: String,
|
||||
default: "0.0.0",
|
||||
});
|
||||
}
|
||||
|
||||
migrate() {
|
||||
const currentVersion = game.settings.get(SYSTEM_RDD, "systemMigrationVersion");
|
||||
if (isNewerVersion(game.system.version, currentVersion)) {
|
||||
//if (true) { /* comment previous and uncomment here to test before upgrade */
|
||||
const migrations = Migrations.getMigrations().filter(m => isNewerVersion(m.version, currentVersion));
|
||||
if (migrations.length > 0) {
|
||||
migrations.sort((a, b) =>
|
||||
isNewerVersion(a.version, b.version)
|
||||
? 1
|
||||
: isNewerVersion(b.version, a.version)
|
||||
? -1
|
||||
: 0
|
||||
);
|
||||
migrations.forEach(async (m) => {
|
||||
ui.notifications.info(
|
||||
`Executing migration ${m.code}: version ${currentVersion} is lower than ${m.version}`
|
||||
);
|
||||
await m.migrate();
|
||||
});
|
||||
ui.notifications.info(
|
||||
`Migrations done, version will change to ${game.system.version}`
|
||||
);
|
||||
} else {
|
||||
console.log(
|
||||
LOG_HEAD +
|
||||
`No migration needeed, version will change to ${game.system.version}`
|
||||
);
|
||||
}
|
||||
|
||||
game.settings.set(
|
||||
SYSTEM_RDD,
|
||||
"systemMigrationVersion",
|
||||
game.system.version
|
||||
);
|
||||
} else {
|
||||
console.log(LOG_HEAD + `No system version changed`);
|
||||
}
|
||||
}
|
||||
}
|
@ -24,7 +24,7 @@ export class Misc {
|
||||
}
|
||||
|
||||
static sum() {
|
||||
return (a, b) => Number(a) + Number(b);
|
||||
return (a, b) => a + b;
|
||||
}
|
||||
|
||||
static ascending(orderFunction = x => x) {
|
||||
@ -41,11 +41,6 @@ export class Misc {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static typeName(type, subType) {
|
||||
return subType ? game.i18n.localize(`${type.toUpperCase()}.Type${Misc.upperFirst(subType)}`)
|
||||
: '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the value to an integer, or to 0 if undefined/null/not representing integer
|
||||
* @param {*} value value to convert to an integer using parseInt
|
||||
@ -73,23 +68,10 @@ export class Misc {
|
||||
}
|
||||
}
|
||||
|
||||
static indexLowercase(list) {
|
||||
const obj = {};
|
||||
const addToObj = (map, val) => {
|
||||
const key = Grammar.toLowerCaseNoAccent(val);
|
||||
if (key && !map[key]) map[key] = val
|
||||
}
|
||||
list.forEach(it => addToObj(obj, it))
|
||||
return obj;
|
||||
}
|
||||
static concat(lists) {
|
||||
return lists.reduce((a, b) => a.concat(b), []);
|
||||
}
|
||||
|
||||
static classify(items, classifier = it => it.type) {
|
||||
let itemsBy = {}
|
||||
Misc.classifyInto(itemsBy, items, classifier)
|
||||
return itemsBy
|
||||
let itemsBy = {};
|
||||
Misc.classifyInto(itemsBy, items, classifier);
|
||||
return itemsBy;
|
||||
}
|
||||
|
||||
static classifyFirst(items, classifier) {
|
||||
@ -105,13 +87,13 @@ export class Misc {
|
||||
|
||||
static classifyInto(itemsBy, items, classifier = it => it.type) {
|
||||
for (const item of items) {
|
||||
const classification = classifier(item)
|
||||
const classification = classifier(item);
|
||||
let list = itemsBy[classification];
|
||||
if (!list) {
|
||||
list = []
|
||||
itemsBy[classification] = list
|
||||
list = [];
|
||||
itemsBy[classification] = list;
|
||||
}
|
||||
list.push(item)
|
||||
list.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,11 +102,29 @@ export class Misc {
|
||||
}
|
||||
|
||||
static join(params, separator = '') {
|
||||
return params?.reduce(Misc.joining(separator)) ?? '';
|
||||
return params.reduce((a, b) => a + separator + b);
|
||||
}
|
||||
|
||||
static joining(separator = '') {
|
||||
return (a, b) => a + separator + b;
|
||||
|
||||
static data(it) {
|
||||
if (it instanceof Actor || it instanceof Item || it instanceof Combatant) {
|
||||
return it.data;
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
static templateData(it) {
|
||||
return Misc.data(it)?.data ?? {}
|
||||
}
|
||||
|
||||
static getEntityTypeLabel(entity) {
|
||||
const documentName = entity?.documentName;
|
||||
const type = entity?.data.type;
|
||||
if (documentName === 'Actor' || documentName === 'Item') {
|
||||
const label = CONFIG[documentName]?.typeLabels?.[type] ?? type;
|
||||
return game.i18n.has(label) ? game.i18n.localize(label) : t;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
static connectedGMOrUser(ownerId = undefined) {
|
||||
@ -134,20 +134,17 @@ export class Misc {
|
||||
return Misc.firstConnectedGM()?.id ?? game.user.id;
|
||||
}
|
||||
|
||||
static isRollModeHiddenToPlayer() {
|
||||
switch (game.settings.get("core", "rollMode")) {
|
||||
case CONST.DICE_ROLL_MODES.BLIND:
|
||||
case CONST.DICE_ROLL_MODES.SELF: return true;
|
||||
}
|
||||
return false
|
||||
static getUsers() {
|
||||
return game.version ? game.users : game.users.entities;
|
||||
}
|
||||
|
||||
static getActiveUser(id) {
|
||||
return game.users.find(u => u.id == id && u.active);
|
||||
}
|
||||
return Misc.getUsers().find(u => u.id == id && u.active);
|
||||
}
|
||||
|
||||
static firstConnectedGM() {
|
||||
return game.users.filter(u => u.isGM && u.active).sort(Misc.ascending(u => u.id)).find(u => u.isGM && u.active);
|
||||
return Misc.getUsers().filter(u => u.isGM && u.active).sort(Misc.ascending(u => u.id)).find(u => u.isGM && u.active);
|
||||
|
||||
}
|
||||
|
||||
static isOwnerPlayer(actor, user=undefined) {
|
||||
@ -162,16 +159,12 @@ export class Misc {
|
||||
* @returns true pour un seul utilisateur: le premier GM connecté par ordre d'id
|
||||
*/
|
||||
static isUniqueConnectedGM() {
|
||||
return game.user.id == Misc.firstConnectedGMId();
|
||||
}
|
||||
|
||||
static firstConnectedGMId() {
|
||||
return Misc.firstConnectedGM()?.id;
|
||||
return game.user.id == Misc.firstConnectedGM()?.id;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static findPlayer(name) {
|
||||
return Misc.findFirstLike(name, game.users, { description: 'joueur' });
|
||||
return Misc.findFirstLike(name, Misc.getUsers(), { description: 'joueur' });
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -224,4 +217,4 @@ export class Misc {
|
||||
}
|
||||
return subset;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +1,72 @@
|
||||
import { Misc } from "./misc.js"
|
||||
import { RdDDice } from "./rdd-dice.js";
|
||||
import { SystemCompendiums } from "./settings/system-compendiums.js";
|
||||
|
||||
const poesieHautReve = [
|
||||
{
|
||||
reference: 'Le Ratier Bretonien',
|
||||
extrait: `Le courant du Fleuve
|
||||
<br>Te domine et te Porte
|
||||
<br>Avant que tu te moeuves
|
||||
<br>Combat le, ou il t'emporte`
|
||||
},
|
||||
{
|
||||
reference: 'Incompatibilité, Charles Beaudelaire',
|
||||
extrait: `Et lorsque par hasard une nuée errante
|
||||
<br>Assombrit dans son vol le lac silencieux,
|
||||
<br>On croirait voir la robe ou l'ombre transparente
|
||||
<br>D'un esprit qui voyage et passe dans les cieux.`
|
||||
},
|
||||
{
|
||||
reference: 'Au fleuve de Loire, Joachim du Bellay',
|
||||
extrait: `Ô de qui la vive course
|
||||
<br>Prend sa bienheureuse source,
|
||||
<br>D’une argentine fontaine,
|
||||
<br>Qui d’une fuite lointaine,
|
||||
<br>Te rends au sein fluctueux
|
||||
<br>De l’Océan monstrueux`
|
||||
},
|
||||
{
|
||||
reference: 'Denis Gerfaud',
|
||||
extrait: `Et l'on peut savoir qui est le maître d'Oniros, c'est le Fleuve de l'Oubli.
|
||||
Et l'on sait qui est le créateur du Fleuve de l'Oubli, c'est Hypnos et Narcos.
|
||||
Mais l'on ne sait pas qui est le maître du Fleuve de l'Oubli,
|
||||
sinon peut-être lui-même, ou peut-être Thanatos` },
|
||||
{
|
||||
reference: 'Denis Gerfaud',
|
||||
extrait: `Narcos est la source du Fleuve de l'Oubli et Hypnos l'embouchure
|
||||
Remonter le Fleuve est la Voie de la Nuit, la Voie du Souvenir.
|
||||
Descendre le Fleuve est la Voie du Jour, la Voie de l'Oubli`
|
||||
},
|
||||
{
|
||||
reference: 'Denis Gerfaud',
|
||||
extrait: `Narcos engendre le fils dont il est la mère à l'heure du Vaisseau,
|
||||
car Oniros s'embarque pour redescendre le Fleuve
|
||||
vers son père Hypnos sur la Voie de l'Oubli`
|
||||
},
|
||||
{
|
||||
reference: 'Denis Gerfaud',
|
||||
extrait: `Hypnos engendre le fils dont il est la mère à l'heure du Serpent, car
|
||||
tel les serpents, Oniros commence à remonter le Fleuve
|
||||
sur le Voie du Souvenir vers son père Narcos`
|
||||
},
|
||||
{
|
||||
reference: 'Denis Gerfaud',
|
||||
extrait: `Ainsi se succèdent les Jours et les Ages.
|
||||
<br>Les jours des Dragons sont les Ages des Hommes.`
|
||||
},
|
||||
{
|
||||
reference: 'Denis Gerfaud',
|
||||
extrait: `Ainsi parlent les sages:
|
||||
«Les Dragons sont créateurs de leurs rêves, mais ils ne sont pas créateurs d'Oniros
|
||||
Les Dragons ne sont pas les maîtres de leurs rêvezs, car ils ne sont pas maîtres d'Oniros.
|
||||
Nul ne sait qui est le créateur des Dragons, ni qui est leur maître.
|
||||
Mais l'on peut supposer qui est le maître du Rêve des Dragons, c'est Oniros»`
|
||||
},
|
||||
]
|
||||
|
||||
export class Poetique {
|
||||
static async getExtrait() {
|
||||
const items = await SystemCompendiums.getItems('extrait-poetique', 'extraitpoetique')
|
||||
const selected = await RdDDice.rollOneOf(items);
|
||||
return {
|
||||
reference: selected?.name,
|
||||
extrait: selected?.system.extrait
|
||||
}
|
||||
static async getExtrait(){
|
||||
return await RdDDice.rollOneOf(poesieHautReve);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
44
module/poetique.txt
Normal file
@ -0,0 +1,44 @@
|
||||
Le courant du Fleuve
|
||||
Te domine et te Porte
|
||||
Avant que tu te moeuves
|
||||
Combat le, ou il t'emporte
|
||||
|
||||
|
||||
|
||||
A vous qui faites ripaille
|
||||
sourds aux damnés de la faim
|
||||
à vous qui livrez
|
||||
une inégale bataille
|
||||
à ceux qui vous tendent la main
|
||||
|
||||
Ils sont tout près ! - Tenons fermée
|
||||
<br>Cette salle, où nous les narguons.
|
||||
<br>Quel bruit dehors ! Hideuse armée
|
||||
<br>De vampires et de dragons !
|
||||
<br>La poutre du toit descellée
|
||||
<br>Ploie ainsi qu'une herbe mouillée,
|
||||
<br>Et la vieille porte rouillée
|
||||
<br>Tremble, à déraciner ses gonds !`),
|
||||
|
||||
https://www.poetica.fr/poeme-1423/guy-de-maupassant-le-sommeil-du-mandarin/
|
||||
|
||||
|
||||
|
||||
|
||||
Le monde est un rêve de Dragons. Nous
|
||||
ne savons pas qui sont les Dragons ni à quoi
|
||||
ils ressemblent, en dépit de l’antique iconographie qui les dépeint comme de gigantesques créatures ailées capables de cracher
|
||||
feu et flammes.
|
||||
|
||||
|
||||
|
||||
Car parmi les humains, autre nom lui est donné,
|
||||
Nom sinistre parmi tous, nom funèbre, c'est la mort!
|
||||
Un ami disparu... Thanatos est passé...
|
||||
|
||||
|
||||
Messieurs, ne crachez pas de jurons ni d'ordure
|
||||
Au visage fardé de cette pauvre impure
|
||||
Que déesse Famine a par un soir d'hiver,
|
||||
Contrainte à relever ses jupons en plein air.
|
||||
|
@ -7,9 +7,9 @@ const matchOperationTerms = new RegExp(/@(\w*){([\w\-]+)}/i);
|
||||
export class RdDAlchimie {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static processManipulation(recette, actorId = undefined) {
|
||||
static processManipulation(recetteData, actorId = undefined) {
|
||||
//console.log("CALLED", recette, recette.isOwned, actorId );
|
||||
let manip = recette.system.manipulation;
|
||||
let manip = recetteData.data.manipulation;
|
||||
let matchArray = manip.match(matchOperations);
|
||||
if (matchArray) {
|
||||
for (let matchStr of matchArray) {
|
||||
@ -17,12 +17,12 @@ export class RdDAlchimie {
|
||||
//console.log("RESULT ", result);
|
||||
if (result[1] && result[2]) {
|
||||
let commande = Misc.upperFirst(result[1]);
|
||||
let replacement = this[`_alchimie${commande}`](recette, result[2], actorId);
|
||||
let replacement = this[`_alchimie${commande}`](recetteData, result[2], actorId);
|
||||
manip = manip.replace(result[0], replacement);
|
||||
}
|
||||
}
|
||||
}
|
||||
recette.system.manipulation_update = manip;
|
||||
recetteData.data.manipulation_update = manip;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
@ -15,19 +15,13 @@
|
||||
|
||||
// Common conf
|
||||
let dialogConf = { content: html, title: "Editeur d'Astrologie", buttons: myButtons, default: "saveButton" };
|
||||
let dialogOptions = { classes: ["rdd-roll-dialog"], width: 600, height: 300, 'z-index': 99999 }
|
||||
let dialogOptions = { classes: ["rdddialog"], width: 600, height: 300, 'z-index': 99999 }
|
||||
super(dialogConf, dialogOptions)
|
||||
|
||||
this.calendrier = calendrier;
|
||||
this.updateData( calendrierData );
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
this.html = html;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async resetNombreAstraux() {
|
||||
game.system.rdd.calendrier.resetNombreAstral();
|
||||
@ -45,4 +39,15 @@
|
||||
this.calendrierData = duplicate(calendrierData);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
let astrologieData = this.astrologieData;
|
||||
|
||||
$(function () {
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -12,50 +12,36 @@ export class RdDAstrologieJoueur extends Dialog {
|
||||
/* -------------------------------------------- */
|
||||
static async create(actor, dialogConfig) {
|
||||
|
||||
let dialogData = {
|
||||
let data = {
|
||||
nombres: this.organizeNombres(actor),
|
||||
dates: game.system.rdd.calendrier.getJoursSuivants(10),
|
||||
etat: actor.getEtatGeneral(),
|
||||
ajustementsConditions: CONFIG.RDD.ajustementsConditions,
|
||||
astrologie: RdDItemCompetence.findCompetence(actor.items, 'Astrologie')
|
||||
astrologie: RdDItemCompetence.findCompetence(actor.data.items, 'Astrologie')
|
||||
}
|
||||
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-astrologie-joueur.html', dialogData);
|
||||
let options = { classes: ["rdd-roll-dialog"], width: 600, height: 500, 'z-index': 99999 };
|
||||
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-astrologie-joueur.html', data);
|
||||
let options = { classes: ["rdddialog"], width: 600, height: 500, 'z-index': 99999 };
|
||||
if (dialogConfig.options) {
|
||||
mergeObject(options, dialogConfig.options, { overwrite: true });
|
||||
}
|
||||
return new RdDAstrologieJoueur(html, actor, dialogData);
|
||||
return new RdDAstrologieJoueur(html, actor, data);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(html, actor, dialogData) {
|
||||
const dialogConf = {
|
||||
title: "Nombres Astraux",
|
||||
content: html,
|
||||
default: "saveButton",
|
||||
buttons: {
|
||||
saveButton: { label: "Fermer", callback: html => this.quitDialog() }
|
||||
},
|
||||
constructor(html, actor, data) {
|
||||
|
||||
let myButtons = {
|
||||
saveButton: { label: "Fermer", callback: html => this.quitDialog() }
|
||||
};
|
||||
const dialogOptions = { classes: ["rdd-roll-dialog"], width: 600, height: 300, 'z-index': 99999 };
|
||||
|
||||
// Get all n
|
||||
// Common conf
|
||||
let dialogConf = { content: html, title: "Nombres Astraux", buttons: myButtons, default: "saveButton" };
|
||||
let dialogOptions = { classes: ["rdddialog"], width: 600, height: 300, 'z-index': 99999 };
|
||||
super(dialogConf, dialogOptions);
|
||||
|
||||
this.actor = actor;
|
||||
this.dataNombreAstral = duplicate(dialogData);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
this.html = html;
|
||||
|
||||
this.html.find(function () {
|
||||
this.html.find("[name='diffConditions']").val(0);
|
||||
});
|
||||
|
||||
this.html.find('[name="jet-astrologie"]').click((event) => {
|
||||
this.requestJetAstrologie();
|
||||
});
|
||||
this.dataNombreAstral = duplicate(data);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -63,12 +49,12 @@ export class RdDAstrologieJoueur extends Dialog {
|
||||
let itemNombres = actor.listItemsData('nombreastral');
|
||||
let itemFiltered = {};
|
||||
for (let item of itemNombres) {
|
||||
if (itemFiltered[item.system.jourindex]) {
|
||||
itemFiltered[item.system.jourindex].listValues.push(item.system.value);
|
||||
if (itemFiltered[item.data.jourindex]) {
|
||||
itemFiltered[item.data.jourindex].listValues.push(item.data.value);
|
||||
} else {
|
||||
itemFiltered[item.system.jourindex] = {
|
||||
listValues: [item.system.value],
|
||||
jourlabel: item.system.jourlabel
|
||||
itemFiltered[item.data.jourindex] = {
|
||||
listValues: [item.data.value],
|
||||
jourlabel: item.data.jourlabel
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -77,21 +63,21 @@ export class RdDAstrologieJoueur extends Dialog {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
requestJetAstrologie() {
|
||||
let socketData = {
|
||||
id: this.actor.id,
|
||||
carac_vue: this.actor.system.carac['vue'].value,
|
||||
let data = {
|
||||
id: this.actor.data._id,
|
||||
carac_vue: Misc.data(this.actor).data.carac['vue'].value,
|
||||
etat: this.dataNombreAstral.etat,
|
||||
astrologie: this.dataNombreAstral.astrologie,
|
||||
conditions: this.html.find('[name="diffConditions"]').val(),
|
||||
date: this.html.find('[name="joursAstrologie"]').val(),
|
||||
conditions: $("#diffConditions").val(),
|
||||
date: $("#joursAstrologie").val(),
|
||||
userId: game.user.id
|
||||
}
|
||||
if (Misc.isUniqueConnectedGM()) {
|
||||
game.system.rdd.calendrier.requestNombreAstral(socketData);
|
||||
game.system.rdd.calendrier.requestNombreAstral(data);
|
||||
} else {
|
||||
game.socket.emit(SYSTEM_SOCKET_ID, {
|
||||
msg: "msg_request_nombre_astral",
|
||||
data: socketData
|
||||
data: data
|
||||
});
|
||||
}
|
||||
this.close();
|
||||
@ -101,4 +87,17 @@ export class RdDAstrologieJoueur extends Dialog {
|
||||
quitDialog() {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
$(function () {
|
||||
$("#diffConditions").val(0);
|
||||
});
|
||||
|
||||
html.find('#jet-astrologie').click((event) => {
|
||||
this.requestJetAstrologie();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ export class RdDBonus {
|
||||
|
||||
static isAjustementAstrologique(rollData) {
|
||||
return RdDCarac.isChance(rollData.selectedCarac) ||
|
||||
rollData.selectedSort?.system.isrituel;
|
||||
rollData.selectedSort?.data.isrituel;
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
static isDefenseAttaqueFinesse(rollData) {
|
||||
@ -68,23 +68,23 @@ export class RdDBonus {
|
||||
}
|
||||
return isCauchemar ? "cauchemar"
|
||||
: rollData.dmg?.mortalite
|
||||
?? rollData.arme?.system.mortalite
|
||||
?? rollData.arme?.data.mortalite
|
||||
?? "mortel";
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static _dmgArme(rollData) {
|
||||
if ( rollData.arme) {
|
||||
let dmgBase = rollData.arme.system.dommagesReels ?? Number(rollData.arme.system.dommages ?? 0);
|
||||
let dmgBase = rollData.arme.data.dommagesReels ?? Number(rollData.arme.data.dommages ?? 0);
|
||||
//Le bonus dégats magiques ne peut pas faire dépasser le bonus de l'arme (cf p.278)
|
||||
return dmgBase + Math.min(dmgBase, rollData.arme.system.magique ? rollData.arme.system.ecaille_efficacite : 0);
|
||||
return dmgBase + Math.min(dmgBase, rollData.arme.data.magique ? rollData.arme.data.ecaille_efficacite : 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static _peneration(rollData) {
|
||||
return parseInt(rollData.arme?.system.penetration ?? 0);
|
||||
return parseInt(rollData.arme?.data.penetration ?? 0);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
@ -8,45 +8,50 @@ export class RdDCalendrierEditeur extends Dialog {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(html, calendrier, calendrierData) {
|
||||
let dialogConf = {
|
||||
content: html,
|
||||
title: "Editeur de date/heure",
|
||||
buttons: {
|
||||
save: { label: "Enregistrer", callback: html => this.fillData() }
|
||||
},
|
||||
default: "save"
|
||||
};
|
||||
let dialogOptions = { classes: ["rdd-dialog-calendar-editor"], width: 400, height: 'fit-content', 'z-index': 99999 }
|
||||
|
||||
let myButtons = {
|
||||
saveButton: { label: "Enregistrer", callback: html => this.fillData() }
|
||||
};
|
||||
|
||||
// Common conf
|
||||
let dialogConf = { content: html, title: "Editeur de date/heure", buttons: myButtons, default: "saveButton" };
|
||||
let dialogOptions = { classes: ["rdddialog"], width: 400, height: 300, 'z-index': 99999 }
|
||||
super(dialogConf, dialogOptions)
|
||||
|
||||
|
||||
this.calendrier = calendrier;
|
||||
this.calendrierData = calendrierData;
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
this.html = html;
|
||||
this.html.find("input[name='nomMois']").val(this.calendrierData.moisKey);
|
||||
this.html.find("select[name='nomHeure']").val(this.calendrierData.heureKey);
|
||||
this.html.find("select[name='jourMois']").val(this.calendrierData.jourMois);
|
||||
this.html.find("select[name='minutesRelative']").val(this.calendrierData.minutesRelative);
|
||||
this.html.find("select[name='annee']").val(this.calendrierData.annee);
|
||||
this.calendrierData = calendrierData; //duplicate(calendrierData);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
fillData() {
|
||||
this.calendrierData.annee = this.html.find("input[name='annee']").val();
|
||||
this.calendrierData.moisKey = this.html.find("select[name='nomMois']").val();
|
||||
this.calendrierData.heureKey = this.html.find("select[name='nomHeure']").val();
|
||||
this.calendrierData.jourMois = this.html.find("select[name='jourMois']").val();
|
||||
this.calendrierData.minutesRelative = this.html.find("select[name='minutesRelative']").val();
|
||||
|
||||
this.calendrier.saveEditeur(this.calendrierData)
|
||||
fillData( ) {
|
||||
this.calendrierData.moisKey = $("#nomMois").val();
|
||||
this.calendrierData.heureKey = $("#nomHeure").val();
|
||||
this.calendrierData.jourMois = $("#jourMois").val();
|
||||
this.calendrierData.minutesRelative = $("#minutesRelative").val();
|
||||
|
||||
console.log("UPDATE ", this.calendrierData);
|
||||
this.calendrier.saveEditeur( this.calendrierData )
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
updateData(calendrierData) {
|
||||
updateData( calendrierData ) {
|
||||
this.calendrierData = duplicate(calendrierData);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
let calendrierData = this.calendrierData;
|
||||
|
||||
$(function () {
|
||||
console.log(calendrierData);
|
||||
$("#nomMois").val(calendrierData.moisKey);
|
||||
$("#nomHeure").val(calendrierData.heureKey);
|
||||
$("#jourMois").val(calendrierData.jourMois);
|
||||
$("#minutesRelative").val(calendrierData.minutesRelative);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,24 +8,23 @@ import { Grammar } from "./grammar.js";
|
||||
import { RdDDice } from "./rdd-dice.js";
|
||||
import { Misc } from "./misc.js";
|
||||
import { HIDE_DICE, SHOW_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
|
||||
import { DialogChronologie } from "./dialog-chronologie.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
const dossierIconesHeures = 'systems/foundryvtt-reve-de-dragon/icons/heures/'
|
||||
const heuresList = ["vaisseau", "sirene", "faucon", "couronne", "dragon", "epees", "lyre", "serpent", "poissonacrobate", "araignee", "roseau", "chateaudormant"];
|
||||
const heuresDef = {
|
||||
"vaisseau": {key: "vaisseau", label: "Vaisseau", lettreFont: 'v', saison: "printemps", heure: 0, icon: 'hd01.svg' },
|
||||
"sirene": { key: "sirene", label: "Sirène", lettreFont: 'i', saison: "printemps", heure: 1, icon: 'hd02.svg' },
|
||||
"faucon": { key: "faucon", label: "Faucon", lettreFont: 'f', saison: "printemps", heure: 2, icon: 'hd03.svg' },
|
||||
"couronne": { key: "couronne", label: "Couronne", lettreFont: '', saison: "ete", heure: 3, icon: 'hd04.svg' },
|
||||
"dragon": { key: "dragon", label: "Dragon", lettreFont: 'd', saison: "ete", heure: 4, icon: 'hd05.svg' },
|
||||
"epees": { key: "epees", label: "Epées", lettreFont: 'e', saison: "ete", heure: 5, icon: 'hd06.svg' },
|
||||
"lyre": { key: "lyre", label: "Lyre", lettreFont: 'l', saison: "automne", heure: 6, icon: 'hd07.svg' },
|
||||
"serpent": { key: "serpent", label: "Serpent", lettreFont: 's', saison: "automne", heure: 7, icon: 'hd08.svg' },
|
||||
"poissonacrobate": { key: "poissonacrobate", label: "Poisson Acrobate", lettreFont: 'p', saison: "automne", heure: 8, icon: 'hd09.svg' },
|
||||
"araignee": { key: "araignee", label: "Araignée", lettreFont: 'a', saison: "hiver", heure: 9, icon: 'hd10.svg' },
|
||||
"roseau": { key: "roseau", label: "Roseau", lettreFont: 'r', saison: "hiver", heure: 10, icon: 'hd11.svg' },
|
||||
"chateaudormant": { key: "chateaudormant", label: "Château Dormant", lettreFont: 'c', saison: "hiver", heure: 11, icon: 'hd12.svg' }
|
||||
"vaisseau": { label: "Vaisseau", lettreFont: 'v', saison: "printemps", heure: 0, icon: 'hd01.svg' },
|
||||
"sirene": { label: "Sirène", lettreFont: 'i', saison: "printemps", heure: 1, icon: 'hd02.svg' },
|
||||
"faucon": { label: "Faucon", lettreFont: 'f', saison: "printemps", heure: 2, icon: 'hd03.svg' },
|
||||
"couronne": { label: "Couronne", lettreFont: '', saison: "ete", heure: 3, icon: 'hd04.svg' },
|
||||
"dragon": { label: "Dragon", lettreFont: 'd', saison: "ete", heure: 4, icon: 'hd05.svg' },
|
||||
"epees": { label: "Epées", lettreFont: 'e', saison: "ete", heure: 5, icon: 'hd06.svg' },
|
||||
"lyre": { label: "Lyre", lettreFont: 'l', saison: "automne", heure: 6, icon: 'hd07.svg' },
|
||||
"serpent": { label: "Serpent", lettreFont: 's', saison: "automne", heure: 7, icon: 'hd08.svg' },
|
||||
"poissonacrobate": { label: "Poisson Acrobate", lettreFont: 'p', saison: "automne", heure: 8, icon: 'hd09.svg' },
|
||||
"araignee": { label: "Araignée", lettreFont: 'a', saison: "hiver", heure: 9, icon: 'hd10.svg' },
|
||||
"roseau": { label: "Roseau", lettreFont: 'r', saison: "hiver", heure: 10, icon: 'hd11.svg' },
|
||||
"chateaudormant": { label: "Château Dormant", lettreFont: 'c', saison: "hiver", heure: 11, icon: 'hd12.svg' }
|
||||
};
|
||||
const saisonsDef = {
|
||||
"printemps": { label: "Printemps" },
|
||||
@ -43,14 +42,6 @@ const MAX_NOMBRE_ASTRAL = 12;
|
||||
/* -------------------------------------------- */
|
||||
export class RdDCalendrier extends Application {
|
||||
|
||||
static get defaultOptions() {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
template: "systems/foundryvtt-reve-de-dragon/templates/calendar-template.html",
|
||||
popOut: false,
|
||||
resizable: false
|
||||
});
|
||||
}
|
||||
|
||||
static createCalendrierPos() {
|
||||
return { top: 200, left: 200 };
|
||||
}
|
||||
@ -60,50 +51,21 @@ export class RdDCalendrier extends Application {
|
||||
return Object.values(heuresDef).find(h => h.heure == chiffre);
|
||||
}
|
||||
|
||||
static getSigneAs(key, value) {
|
||||
const heure = (typeof value == 'string' || typeof value == 'number') && Number.isInteger(Number(value))
|
||||
? Number(value)
|
||||
: (typeof value == 'string') ? RdDCalendrier.getChiffreFromSigne(value)
|
||||
: undefined
|
||||
|
||||
if (heure != undefined && ['key', 'label', 'lettreFont', 'saison', 'heure', 'icon'].includes(key)) {
|
||||
return RdDCalendrier.getDefSigne(heure)[key]
|
||||
}
|
||||
if (heure != undefined && ['webp'].includes(key)) {
|
||||
return RdDCalendrier.getDefSigne(heure)['icon'].replace('svg', 'webp');
|
||||
}
|
||||
console.error(`Appel à getSigneAs('${key}', ${value}) avec une clé/heure incorrects`);
|
||||
return value;
|
||||
|
||||
}
|
||||
static getChiffreFromSigne(signe) {
|
||||
return heuresList.indexOf(signe);
|
||||
}
|
||||
|
||||
static createCalendrierInitial() {
|
||||
return {
|
||||
heureRdD: 0,
|
||||
minutesRelative: 0,
|
||||
indexJour: 0,
|
||||
annee: 0,
|
||||
moisRdD: 0,
|
||||
moisLabel: heuresDef["vaisseau"].label,
|
||||
jour: 0
|
||||
}
|
||||
}
|
||||
|
||||
getCalendrier(index) {
|
||||
index = index ?? this.getCurrentDayIndex();
|
||||
const mois = Math.floor(index / RDD_JOUR_PAR_MOIS) % RDD_MOIS_PAR_AN;
|
||||
return {
|
||||
static getCalendrier(index) {
|
||||
let calendrier = {
|
||||
heureRdD: 0, // Index dans heuresList / heuresDef[x].heure
|
||||
minutesRelative: 0,
|
||||
indexJour: index,
|
||||
annee: Math.floor(index / (RDD_JOUR_PAR_MOIS * RDD_MOIS_PAR_AN)),
|
||||
moisRdD: RdDCalendrier.getDefSigne(mois).heure,
|
||||
moisLabel: RdDCalendrier.getDefSigne(mois).label,
|
||||
moisRdD: Math.floor(index / RDD_JOUR_PAR_MOIS) % RDD_MOIS_PAR_AN,
|
||||
jour: (index % RDD_JOUR_PAR_MOIS) // Le calendrier stocke le jour en 0-27, mais en 1-28 à l'affichage
|
||||
}
|
||||
calendrier.moisLabel = RdDCalendrier.getDefSigne(calendrier.moisRdD).label;
|
||||
return calendrier;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
@ -116,7 +78,7 @@ export class RdDCalendrier extends Application {
|
||||
}
|
||||
|
||||
// Calendrier
|
||||
this.calendrier = duplicate(game.settings.get(SYSTEM_RDD, "calendrier") ?? RdDCalendrier.createCalendrierInitial());
|
||||
this.calendrier = duplicate(game.settings.get(SYSTEM_RDD, "calendrier") ?? RdDCalendrier.getCalendrier(0));
|
||||
this.calendrier.annee = this.calendrier.annee ?? Math.floor((this.calendrier.moisRdD ?? 0) / RDD_MOIS_PAR_AN);
|
||||
this.calendrier.moisRdD = (this.calendrier.moisRdD ?? 0) % RDD_MOIS_PAR_AN;
|
||||
|
||||
@ -124,117 +86,34 @@ export class RdDCalendrier extends Application {
|
||||
game.settings.set(SYSTEM_RDD, "calendrier", this.calendrier);
|
||||
|
||||
this.listeNombreAstral = this.getListeNombreAstral();
|
||||
this.rebuildListeNombreAstral(HIDE_DICE); // Ensure always up-to-date
|
||||
this.rebuildListeNombreAstral(false); // Ensure always up-to-date
|
||||
}
|
||||
console.log('RdDCalendrier.constructor()', this.calendrier, this.calendrierPos, this.listeNombreAstral);
|
||||
console.log(this.calendrier, this.calendrierPos, this.listeNombreAstral);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
async activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
this.html = html;
|
||||
|
||||
this.updateDisplay();
|
||||
|
||||
this.html.find('.ajout-chronologie').click(ev => DialogChronologie.create());
|
||||
|
||||
this.html.find('.calendar-btn').click(ev => this.onCalendarButton(ev));
|
||||
|
||||
this.html.find('.calendar-btn-edit').click(ev => {
|
||||
ev.preventDefault();
|
||||
this.showCalendarEditor();
|
||||
});
|
||||
|
||||
this.html.find('.astrologie-btn-edit').click(ev => {
|
||||
ev.preventDefault();
|
||||
this.showAstrologieEditor();
|
||||
});
|
||||
|
||||
this.html.find('#calendar-move-handle').mousedown(ev => {
|
||||
ev.preventDefault();
|
||||
ev = ev || window.event;
|
||||
let isRightMB = false;
|
||||
if ("which" in ev) { // Gecko (Firefox), WebKit (Safari/Chrome) & Opera
|
||||
isRightMB = ev.which == 3;
|
||||
} else if ("button" in ev) { // IE, Opera
|
||||
isRightMB = ev.button == 2;
|
||||
}
|
||||
|
||||
if (!isRightMB) {
|
||||
dragElement(document.getElementById("calendar-time-container"));
|
||||
let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
|
||||
|
||||
function dragElement(elmnt) {
|
||||
elmnt.onmousedown = dragMouseDown;
|
||||
function dragMouseDown(e) {
|
||||
e = e || window.event;
|
||||
e.preventDefault();
|
||||
pos3 = e.clientX;
|
||||
pos4 = e.clientY;
|
||||
|
||||
document.onmouseup = closeDragElement;
|
||||
document.onmousemove = elementDrag;
|
||||
}
|
||||
|
||||
function elementDrag(e) {
|
||||
e = e || window.event;
|
||||
e.preventDefault();
|
||||
// calculate the new cursor position:
|
||||
pos1 = pos3 - e.clientX;
|
||||
pos2 = pos4 - e.clientY;
|
||||
pos3 = e.clientX;
|
||||
pos4 = e.clientY;
|
||||
// set the element's new position:
|
||||
elmnt.style.bottom = undefined
|
||||
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
|
||||
elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
|
||||
}
|
||||
|
||||
function closeDragElement() {
|
||||
// stop moving when mouse button is released:
|
||||
elmnt.onmousedown = undefined;
|
||||
document.onmouseup = undefined;
|
||||
document.onmousemove = undefined;
|
||||
let xPos = (elmnt.offsetLeft - pos1) > window.innerWidth ? window.innerWidth - 200 : (elmnt.offsetLeft - pos1);
|
||||
let yPos = (elmnt.offsetTop - pos2) > window.innerHeight - 20 ? window.innerHeight - 100 : (elmnt.offsetTop - pos2)
|
||||
xPos = xPos < 0 ? 0 : xPos;
|
||||
yPos = yPos < 0 ? 0 : yPos;
|
||||
if (xPos != (elmnt.offsetLeft - pos1) || yPos != (elmnt.offsetTop - pos2)) {
|
||||
elmnt.style.top = (yPos) + "px";
|
||||
elmnt.style.left = (xPos) + "px";
|
||||
}
|
||||
game.system.rdd.calendrier.calendrierPos.top = yPos;
|
||||
game.system.rdd.calendrier.calendrierPos.left = xPos;
|
||||
if (game.user.isGM) {
|
||||
game.settings.set(SYSTEM_RDD, "calendrier-pos", duplicate(game.system.rdd.calendrier.calendrierPos));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (isRightMB) {
|
||||
game.system.rdd.calendrier.calendrierPos.top = 200;
|
||||
game.system.rdd.calendrier.calendrierPos.left = 200;
|
||||
if (game.user.isGM) {
|
||||
game.settings.set(SYSTEM_RDD, "calendrier-pos", duplicate(game.system.rdd.calendrier.calendrierPos));
|
||||
}
|
||||
this.setPos(game.system.rdd.calendrier.calendrierPos);
|
||||
}
|
||||
});
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getListeNombreAstral() {
|
||||
return game.settings.get(SYSTEM_RDD, "liste-nombre-astral") ?? [];
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getDateFromIndex(index) {
|
||||
const dateRdD = this.getCalendrier(index);
|
||||
return (dateRdD.jour + 1) + ' ' + dateRdD.moisLabel;
|
||||
static get defaultOptions() {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
template: "systems/foundryvtt-reve-de-dragon/templates/calendar-template.html",
|
||||
popOut: false,
|
||||
resizable: false
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getDayMonthFromIndex(index = undefined) {
|
||||
const dateRdD = this.getCalendrier(index);
|
||||
getDateFromIndex(index) {
|
||||
const date = RdDCalendrier.getCalendrier(index ?? this.getCurrentDayIndex());
|
||||
return (date.jour + 1) + ' ' + RdDCalendrier.getDefSigne(date.moisRdD).label;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getNumericDateFromIndex(index = undefined) {
|
||||
const dateRdD = RdDCalendrier.getCalendrier(index ?? this.getCurrentDayIndex());
|
||||
return {
|
||||
day: dateRdD.jour + 1,
|
||||
month: heuresList[dateRdD.moisRdD]
|
||||
@ -301,14 +180,14 @@ export class RdDCalendrier extends Application {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getNombreAstral(indexDate) {
|
||||
const listNombreAstral = this.getListeNombreAstral();
|
||||
let astralData = listNombreAstral.find((nombreAstral, i) => nombreAstral.index == indexDate);
|
||||
let astralData = this.getListeNombreAstral().find((nombreAstral, i) => nombreAstral.index == indexDate);
|
||||
return astralData?.nombreAstral;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async rebuildListeNombreAstral(showDice = HIDE_DICE) {
|
||||
async rebuildListeNombreAstral(showDice = SHOW_DICE) {
|
||||
if (Misc.isUniqueConnectedGM()) {
|
||||
console.log("rebuildListeNombreAstral", showDice);
|
||||
let jourCourant = this.getCurrentDayIndex();
|
||||
let newList = [];
|
||||
for (let i = 0; i < MAX_NOMBRE_ASTRAL; i++) {
|
||||
@ -320,8 +199,9 @@ export class RdDCalendrier extends Application {
|
||||
newList[i] = await this.ajouterNombreAstral(dayIndex, showDice);
|
||||
}
|
||||
}
|
||||
game.settings.set(SYSTEM_RDD, "liste-nombre-astral", newList);
|
||||
//console.log("SAVE list", newList, jourCourant);
|
||||
this.listeNombreAstral = newList;
|
||||
game.settings.set(SYSTEM_RDD, "liste-nombre-astral", this.listeNombreAstral);
|
||||
}
|
||||
}
|
||||
|
||||
@ -343,9 +223,9 @@ export class RdDCalendrier extends Application {
|
||||
checkMaladie( periode) {
|
||||
for (let actor of game.actors) {
|
||||
if (actor.type == 'personnage') {
|
||||
let maladies = actor.items.filter( item => (item.type == 'maladie' || (item.type == 'poison' && item.system.active) ) && item.system.periodicite.toLowerCase().includes(periode) );
|
||||
let maladies = actor.filterItems( item => (item.type == 'maladie' || (item.type == 'poison' && item.data.active) ) && item.data.periodicite.toLowerCase().includes(periode) );
|
||||
for (let maladie of maladies) {
|
||||
if ( maladie.system.identifie) {
|
||||
if ( maladie.data.identifie) {
|
||||
ChatMessage.create({ content: `${actor.name} souffre de ${maladie.name} (${maladie.type}): vérifiez que les effets ne se sont pas aggravés !` });
|
||||
} else {
|
||||
ChatMessage.create({ content: `${actor.name} souffre d'un mal inconnu (${maladie.type}): vérifiez que les effets ne se sont pas aggravés !` });
|
||||
@ -384,7 +264,7 @@ export class RdDCalendrier extends Application {
|
||||
/* -------------------------------------------- */
|
||||
async incrementerJour() {
|
||||
const index = this.getCurrentDayIndex() + 1;
|
||||
this.calendrier = this.getCalendrier(index);
|
||||
this.calendrier = RdDCalendrier.getCalendrier(index);
|
||||
await this.rebuildListeNombreAstral();
|
||||
}
|
||||
|
||||
@ -406,15 +286,18 @@ export class RdDCalendrier extends Application {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
fillCalendrierData(formData = {}) {
|
||||
const mois = RdDCalendrier.getDefSigne(this.calendrier.moisRdD);
|
||||
const heure = RdDCalendrier.getDefSigne(this.calendrier.heureRdD);
|
||||
console.log('fillCalendrierData', this.calendrier, mois, heure);
|
||||
console.log(this.calendrier);
|
||||
let moisKey = heuresList[this.calendrier.moisRdD];
|
||||
let heureKey = heuresList[this.calendrier.heureRdD];
|
||||
console.log(moisKey, heureKey);
|
||||
|
||||
formData.heureKey = heure.key;
|
||||
formData.moisKey = mois.key;
|
||||
const mois = heuresDef[moisKey];
|
||||
const heure = heuresDef[heureKey];
|
||||
|
||||
formData.heureKey = heureKey;
|
||||
formData.moisKey = moisKey;
|
||||
formData.jourMois = this.calendrier.jour + 1;
|
||||
formData.nomMois = mois.label; // heures et mois nommés identiques
|
||||
formData.annee = this.calendrier.annee;
|
||||
formData.iconMois = dossierIconesHeures + mois.icon;
|
||||
formData.nomHeure = heure.label;
|
||||
formData.iconHeure = dossierIconesHeures + heure.icon;
|
||||
@ -437,7 +320,7 @@ export class RdDCalendrier extends Application {
|
||||
if (Misc.isUniqueConnectedGM()) { // Only once
|
||||
console.log(request);
|
||||
let jourDiff = this.getLectureAstrologieDifficulte(request.date);
|
||||
let niveau = Number(request.astrologie.system.niveau) + Number(request.conditions) + Number(jourDiff) + Number(request.etat);
|
||||
let niveau = Number(request.astrologie.data.niveau) + Number(request.conditions) + Number(jourDiff) + Number(request.etat);
|
||||
let rollData = {
|
||||
caracValue: request.carac_vue,
|
||||
finalLevel: niveau,
|
||||
@ -545,7 +428,7 @@ export class RdDCalendrier extends Application {
|
||||
function check() {
|
||||
let elmnt = document.getElementById("calendar-time-container");
|
||||
if (elmnt) {
|
||||
elmnt.style.bottom = undefined;
|
||||
elmnt.style.bottom = null;
|
||||
let xPos = (pos.left) > window.innerWidth ? window.innerWidth - 200 : pos.left;
|
||||
let yPos = (pos.top) > window.innerHeight - 20 ? window.innerHeight - 100 : pos.top;
|
||||
elmnt.style.top = (yPos) + "px";
|
||||
@ -561,9 +444,9 @@ export class RdDCalendrier extends Application {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
updateDisplay() {
|
||||
let calendrier = this.fillCalendrierData();
|
||||
// Rebuild text du calendrier
|
||||
let dateHTML = `${calendrier.jourMois} ${calendrier.nomMois} ${calendrier.annee} (${calendrier.nomSaison})`
|
||||
let data = this.fillCalendrierData();
|
||||
// Rebuild data
|
||||
let dateHTML = `Jour ${data.jourMois} de ${data.nomMois} (${data.nomSaison})`
|
||||
if (game.user.isGM) {
|
||||
dateHTML = dateHTML + " - NA: " + (this.getCurrentNombreAstral() ?? "indéterminé");
|
||||
}
|
||||
@ -571,13 +454,13 @@ export class RdDCalendrier extends Application {
|
||||
handle.innerHTML = dateHTML;
|
||||
}
|
||||
for (let heure of document.getElementsByClassName("calendar-heure-texte")) {
|
||||
heure.innerHTML = calendrier.nomHeure;
|
||||
heure.innerHTML = data.nomHeure;
|
||||
}
|
||||
for (const minute of document.getElementsByClassName("calendar-time-disp")) {
|
||||
minute.innerHTML = `${calendrier.minutesRelative} minutes`;
|
||||
minute.innerHTML = `${data.minutesRelative} minutes`;
|
||||
}
|
||||
for (const heureImg of document.getElementsByClassName("calendar-heure-img")) {
|
||||
heureImg.src = calendrier.iconHeure;
|
||||
heureImg.src = data.iconHeure;
|
||||
}
|
||||
}
|
||||
|
||||
@ -586,7 +469,6 @@ export class RdDCalendrier extends Application {
|
||||
this.calendrier.minutesRelative = Number(calendrierData.minutesRelative);
|
||||
this.calendrier.jour = Number(calendrierData.jourMois) - 1;
|
||||
this.calendrier.moisRdD = RdDCalendrier.getChiffreFromSigne(calendrierData.moisKey);
|
||||
this.calendrier.annee = Number(calendrierData.annee);
|
||||
this.calendrier.heureRdD = RdDCalendrier.getChiffreFromSigne(calendrierData.heureKey);
|
||||
game.settings.set(SYSTEM_RDD, "calendrier", duplicate(this.calendrier));
|
||||
|
||||
@ -646,4 +528,97 @@ export class RdDCalendrier extends Application {
|
||||
astrologieEditeur.updateData(calendrierData);
|
||||
astrologieEditeur.render(true);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
async activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
HtmlUtility._showControlWhen($(".gm-only"), game.user.isGM);
|
||||
|
||||
await this.updateDisplay();
|
||||
|
||||
html.find('.calendar-btn').click(ev => this.onCalendarButton(ev));
|
||||
|
||||
html.find('.calendar-btn-edit').click(ev => {
|
||||
ev.preventDefault();
|
||||
this.showCalendarEditor();
|
||||
});
|
||||
|
||||
html.find('.astrologie-btn-edit').click(ev => {
|
||||
ev.preventDefault();
|
||||
this.showAstrologieEditor();
|
||||
});
|
||||
|
||||
html.find('#calendar-move-handle').mousedown(ev => {
|
||||
ev.preventDefault();
|
||||
ev = ev || window.event;
|
||||
let isRightMB = false;
|
||||
if ("which" in ev) { // Gecko (Firefox), WebKit (Safari/Chrome) & Opera
|
||||
isRightMB = ev.which == 3;
|
||||
} else if ("button" in ev) { // IE, Opera
|
||||
isRightMB = ev.button == 2;
|
||||
}
|
||||
|
||||
if (!isRightMB) {
|
||||
dragElement(document.getElementById("calendar-time-container"));
|
||||
let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
|
||||
|
||||
function dragElement(elmnt) {
|
||||
elmnt.onmousedown = dragMouseDown;
|
||||
function dragMouseDown(e) {
|
||||
e = e || window.event;
|
||||
e.preventDefault();
|
||||
pos3 = e.clientX;
|
||||
pos4 = e.clientY;
|
||||
|
||||
document.onmouseup = closeDragElement;
|
||||
document.onmousemove = elementDrag;
|
||||
}
|
||||
|
||||
function elementDrag(e) {
|
||||
e = e || window.event;
|
||||
e.preventDefault();
|
||||
// calculate the new cursor position:
|
||||
pos1 = pos3 - e.clientX;
|
||||
pos2 = pos4 - e.clientY;
|
||||
pos3 = e.clientX;
|
||||
pos4 = e.clientY;
|
||||
// set the element's new position:
|
||||
elmnt.style.bottom = null
|
||||
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
|
||||
elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
|
||||
}
|
||||
|
||||
function closeDragElement() {
|
||||
// stop moving when mouse button is released:
|
||||
elmnt.onmousedown = null;
|
||||
document.onmouseup = null;
|
||||
document.onmousemove = null;
|
||||
let xPos = (elmnt.offsetLeft - pos1) > window.innerWidth ? window.innerWidth - 200 : (elmnt.offsetLeft - pos1);
|
||||
let yPos = (elmnt.offsetTop - pos2) > window.innerHeight - 20 ? window.innerHeight - 100 : (elmnt.offsetTop - pos2)
|
||||
xPos = xPos < 0 ? 0 : xPos;
|
||||
yPos = yPos < 0 ? 0 : yPos;
|
||||
if (xPos != (elmnt.offsetLeft - pos1) || yPos != (elmnt.offsetTop - pos2)) {
|
||||
elmnt.style.top = (yPos) + "px";
|
||||
elmnt.style.left = (xPos) + "px";
|
||||
}
|
||||
game.system.rdd.calendrier.calendrierPos.top = yPos;
|
||||
game.system.rdd.calendrier.calendrierPos.left = xPos;
|
||||
if (game.user.isGM) {
|
||||
game.settings.set(SYSTEM_RDD, "calendrier-pos", duplicate(game.system.rdd.calendrier.calendrierPos));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (isRightMB) {
|
||||
game.system.rdd.calendrier.calendrierPos.top = 200;
|
||||
game.system.rdd.calendrier.calendrierPos.left = 200;
|
||||
if (game.user.isGM) {
|
||||
game.settings.set(SYSTEM_RDD, "calendrier-pos", duplicate(game.system.rdd.calendrier.calendrierPos));
|
||||
}
|
||||
this.setPos(game.system.rdd.calendrier.calendrierPos);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -52,11 +52,6 @@ export class RdDCarac {
|
||||
return selectedCarac?.label?.toLowerCase()?.match(/r(e|ê)ve(( |-)actuel)?/);
|
||||
}
|
||||
|
||||
static isActionPhysique(selectedCarac) {
|
||||
return !selectedCarac ||
|
||||
selectedCarac?.label.match(/(Apparence|Force|Agilité|Dextérité|Vue|Ouïe|Odorat-Goût|Empathie|Dérobée|Mêlée|Tir|Lancer)/);
|
||||
}
|
||||
|
||||
static isIgnoreEtatGeneral(rollData) {
|
||||
const selectedCarac = rollData.selectedCarac;
|
||||
return !selectedCarac ||
|
||||
@ -67,7 +62,7 @@ export class RdDCarac {
|
||||
|
||||
|
||||
static computeTotal(carac, beaute = undefined) {
|
||||
const total = Object.values(carac ?? {}).filter(c => !c.derivee)
|
||||
const total = Object.values(carac).filter(c => !c.derivee)
|
||||
.map(it => parseInt(it.value))
|
||||
.reduce(Misc.sum(), 0);
|
||||
const beauteSuperieur10 = Math.max((beaute ?? 10) - 10, 0);
|
||||
@ -106,35 +101,35 @@ export class RdDCarac {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static computeCarac(system) {
|
||||
system.carac.force.value = Math.min(system.carac.force.value, parseInt(system.carac.taille.value) + 4);
|
||||
static computeCarac(data) {
|
||||
data.carac.force.value = Math.min(data.carac.force.value, parseInt(data.carac.taille.value) + 4);
|
||||
|
||||
system.carac.derobee.value = Math.floor(parseInt(((21 - system.carac.taille.value)) + parseInt(system.carac.agilite.value)) / 2);
|
||||
let bonusDomKey = Math.floor((parseInt(system.carac.force.value) + parseInt(system.carac.taille.value)) / 2);
|
||||
data.carac.derobee.value = Math.floor(parseInt(((21 - data.carac.taille.value)) + parseInt(data.carac.agilite.value)) / 2);
|
||||
let bonusDomKey = Math.floor((parseInt(data.carac.force.value) + parseInt(data.carac.taille.value)) / 2);
|
||||
bonusDomKey = Math.min(Math.max(bonusDomKey, 0), 32); // Clamp de securite
|
||||
|
||||
let tailleData = tableCaracDerivee[bonusDomKey];
|
||||
system.attributs.plusdom.value = tailleData.plusdom;
|
||||
data.attributs.plusdom.value = tailleData.plusdom;
|
||||
|
||||
system.attributs.sconst.value = RdDCarac.calculSConst(system.carac.constitution.value);
|
||||
system.attributs.sust.value = tableCaracDerivee[Number(system.carac.taille.value)].sust;
|
||||
data.attributs.sconst.value = RdDCarac.calculSConst(data.carac.constitution.value);
|
||||
data.attributs.sust.value = tableCaracDerivee[Number(data.carac.taille.value)].sust;
|
||||
|
||||
system.attributs.encombrement.value = (parseInt(system.carac.force.value) + parseInt(system.carac.taille.value)) / 2;
|
||||
system.carac.melee.value = Math.floor((parseInt(system.carac.force.value) + parseInt(system.carac.agilite.value)) / 2);
|
||||
system.carac.tir.value = Math.floor((parseInt(system.carac.vue.value) + parseInt(system.carac.dexterite.value)) / 2);
|
||||
system.carac.lancer.value = Math.floor((parseInt(system.carac.tir.value) + parseInt(system.carac.force.value)) / 2);
|
||||
data.attributs.encombrement.value = (parseInt(data.carac.force.value) + parseInt(data.carac.taille.value)) / 2;
|
||||
data.carac.melee.value = Math.floor((parseInt(data.carac.force.value) + parseInt(data.carac.agilite.value)) / 2);
|
||||
data.carac.tir.value = Math.floor((parseInt(data.carac.vue.value) + parseInt(data.carac.dexterite.value)) / 2);
|
||||
data.carac.lancer.value = Math.floor((parseInt(data.carac.tir.value) + parseInt(data.carac.force.value)) / 2);
|
||||
|
||||
system.sante.vie.max = Math.ceil((parseInt(system.carac.taille.value) + parseInt(system.carac.constitution.value)) / 2);
|
||||
data.sante.vie.max = Math.ceil((parseInt(data.carac.taille.value) + parseInt(data.carac.constitution.value)) / 2);
|
||||
|
||||
system.sante.vie.value = Math.min(system.sante.vie.value, system.sante.vie.max)
|
||||
system.sante.endurance.max = Math.max(parseInt(system.carac.taille.value) + parseInt(system.carac.constitution.value), parseInt(system.sante.vie.max) + parseInt(system.carac.volonte.value));
|
||||
system.sante.endurance.value = Math.min(system.sante.endurance.value, system.sante.endurance.max);
|
||||
system.sante.fatigue.max = system.sante.endurance.max * 2;
|
||||
system.sante.fatigue.value = Math.min(system.sante.fatigue.value, system.sante.fatigue.max);
|
||||
data.sante.vie.value = Math.min(data.sante.vie.value, data.sante.vie.max)
|
||||
data.sante.endurance.max = Math.max(parseInt(data.carac.taille.value) + parseInt(data.carac.constitution.value), parseInt(data.sante.vie.max) + parseInt(data.carac.volonte.value));
|
||||
data.sante.endurance.value = Math.min(data.sante.endurance.value, data.sante.endurance.max);
|
||||
data.sante.fatigue.max = data.sante.endurance.max * 2;
|
||||
data.sante.fatigue.value = Math.min(data.sante.fatigue.value, data.sante.fatigue.max);
|
||||
|
||||
//Compteurs
|
||||
system.reve.reve.max = system.carac.reve.value;
|
||||
system.compteurs.chance.max = system.carac.chance.value;
|
||||
data.reve.reve.max = data.carac.reve.value;
|
||||
data.compteurs.chance.max = data.carac.chance.value;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { ChatUtility } from "./chat-utility.js";
|
||||
import { ENTITE_BLURETTE, ENTITE_INCARNE, ENTITE_NONINCARNE, HIDE_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
|
||||
import { DialogSelectTarget } from "./dialog-select-target.js";
|
||||
import { ENTITE_INCARNE, ENTITE_NONINCARNE, HIDE_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
|
||||
import { Grammar } from "./grammar.js";
|
||||
import { RdDItemArme } from "./item-arme.js";
|
||||
import { RdDItemCompetence } from "./item-competence.js";
|
||||
@ -10,9 +9,7 @@ import { RdDBonus } from "./rdd-bonus.js";
|
||||
import { RdDResolutionTable } from "./rdd-resolution-table.js";
|
||||
import { RdDRoll } from "./rdd-roll.js";
|
||||
import { RdDRollTables } from "./rdd-rolltables.js";
|
||||
import { ReglesOptionelles } from "./settings/regles-optionelles.js";
|
||||
import { STATUSES } from "./settings/status-effects.js";
|
||||
import { Targets } from "./targets.js";
|
||||
import { ReglesOptionelles } from "./regles-optionelles.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
const premierRoundInit = [
|
||||
@ -69,7 +66,7 @@ export class RdDCombatManager extends Combat {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async finDeRound(options = { terminer: false }) {
|
||||
for (let combatant of this.combatants) {
|
||||
for (let combatant of this.data.combatants) {
|
||||
if (combatant.actor) {
|
||||
await combatant.actor.finDeRound(options);
|
||||
}
|
||||
@ -81,27 +78,28 @@ export class RdDCombatManager extends Combat {
|
||||
|
||||
/************************************************************************************/
|
||||
async rollInitiative(ids, formula = undefined, messageOptions = {}) {
|
||||
console.log(`${game.system.title} | Combat.rollInitiative()`, ids, formula, messageOptions);
|
||||
|
||||
console.log(`${game.data.system.data.title} | Combat.rollInitiative()`, ids, formula, messageOptions);
|
||||
// Structure input data
|
||||
ids = typeof ids === "string" ? [ids] : ids;
|
||||
const currentId = this.combatant._id;
|
||||
// calculate initiative
|
||||
for (let cId = 0; cId < ids.length; cId++) {
|
||||
const combatant = this.combatants.get(ids[cId]);
|
||||
let rollFormula = formula ?? RdDCombatManager.formuleInitiative(2, 10, 0, 0);
|
||||
if (!formula) {
|
||||
if (combatant.actor.type == 'creature' || combatant.actor.type == 'entite') {
|
||||
const competence = combatant.actor.items.find(it => it.system.iscombat)
|
||||
if (combatant.actor.data.type == 'creature' || combatant.actor.data.type == 'entite') {
|
||||
const competence = combatant.actor.data.items.find(it => it.data.data.iscombat)
|
||||
if (competence) {
|
||||
rollFormula = RdDCombatManager.formuleInitiative(2, competence.system.carac_value, competence.system.niveau, 0);
|
||||
rollFormula = RdDCombatManager.formuleInitiative(2, competence.data.carac_value, competence.data.niveau, 0);
|
||||
}
|
||||
} else {
|
||||
const armeCombat = combatant.actor.itemTypes['arme'].find(it => it.system.equipe)
|
||||
const compName = (armeCombat == undefined) ? "Corps à corps" : armeCombat.system.competence;
|
||||
const competence = RdDItemCompetence.findCompetence(combatant.actor.items, compName);
|
||||
const armeCombat = combatant.actor.data.items.find(it => it.type == 'arme' && itemData.data.equipe)
|
||||
const compName = (armeCombat == undefined) ? "Corps à corps" : armeCombat.data.competence;
|
||||
const competence = RdDItemCompetence.findCompetence(combatant.actor.data.items, compName);
|
||||
if (competence) {
|
||||
const carac = combatant.actor.system.carac[competence.system.defaut_carac].value;
|
||||
const niveau = competence.system.niveau;
|
||||
const bonusEcaille = (armeCombat?.system.magique) ? armeCombat.system.ecaille_efficacite : 0;
|
||||
const carac = combatant.actor.data.data.carac[competence.data.defaut_carac].value;
|
||||
const niveau = competence.data.niveau;
|
||||
const bonusEcaille = (armeCombat?.data.magique) ? armeCombat.data.ecaille_efficacite : 0;
|
||||
rollFormula = RdDCombatManager.formuleInitiative(2, carac, niveau, bonusEcaille);
|
||||
}
|
||||
}
|
||||
@ -122,7 +120,7 @@ export class RdDCombatManager extends Combat {
|
||||
{
|
||||
speaker: {
|
||||
scene: canvas.scene._id,
|
||||
actor: combatant.actor?._id,
|
||||
actor: combatant.actor ? combatant.actor._id : null,
|
||||
token: combatant.token._id,
|
||||
alias: combatant.token.name,
|
||||
sound: CONFIG.sounds.dice,
|
||||
@ -152,77 +150,50 @@ export class RdDCombatManager extends Combat {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** Retourne une liste triée d'actions d'armes avec le split arme1 main / arme 2 main / lancer */
|
||||
/** Retourne une liste triée d'actions d'armes avec le split arme1 main / arme 2 main */
|
||||
static listActionsArmes(armes, competences, carac) {
|
||||
let actions = [];
|
||||
// Gestion des armes 1/2 mains
|
||||
let actionsArme = [];
|
||||
for (const arme of armes) {
|
||||
if (arme.system.equipe) {
|
||||
const dommages = arme.system.dommages.toString();
|
||||
const tableauDommages = dommages.includes("/") ? dommages.split("/") : [dommages, dommages];
|
||||
if (arme.system.unemain && arme.system.deuxmains && !dommages.includes("/")) {
|
||||
ui.notifications.info("Les dommages de l'arme à 1/2 mains " + arme.name + " ne sont pas corrects (ie sous la forme X/Y)");
|
||||
}
|
||||
if ((arme.system.unemain && arme.system.competence) ||
|
||||
(arme.system.competence.toLowerCase().includes("corps à corps"))) {
|
||||
actions.push(RdDCombatManager.$prepareAttaqueArme({
|
||||
arme: arme,
|
||||
infoMain: "(1 main)",
|
||||
dommagesReel: Number(tableauDommages[0]),
|
||||
competence: arme.system.competence,
|
||||
carac: carac,
|
||||
competences: competences
|
||||
}));
|
||||
}
|
||||
if (arme.system.deuxmains && arme.system.competence) {
|
||||
actions.push(RdDCombatManager.$prepareAttaqueArme({
|
||||
arme: arme,
|
||||
infoMain: "(2 mains)",
|
||||
dommagesReel: Number(tableauDommages[1]),
|
||||
competence: arme.system.competence.replace(" 1 main", " 2 mains"),
|
||||
carac: carac,
|
||||
competences: competences
|
||||
}));
|
||||
}
|
||||
if (arme.system.lancer) {
|
||||
actions.push(RdDCombatManager.$prepareAttaqueArme({
|
||||
arme: arme,
|
||||
infoMain: "(lancer)",
|
||||
dommagesReel: Number(tableauDommages[0]),
|
||||
competence: arme.system.lancer,
|
||||
carac: carac,
|
||||
competences: competences
|
||||
}));
|
||||
}
|
||||
if (arme.system.tir) {
|
||||
actions.push(RdDCombatManager.$prepareAttaqueArme({
|
||||
arme: arme,
|
||||
infoMain: "(tir)",
|
||||
dommagesReel: Number(tableauDommages[0]),
|
||||
competence: arme.system.tir,
|
||||
carac: carac,
|
||||
competences: competences
|
||||
}));
|
||||
let action = duplicate(Misc.data(arme));
|
||||
if (action.data.equipe) {
|
||||
let compData = competences.map(c => Misc.data(c)).find(c => c.name == action.data.competence);
|
||||
|
||||
actionsArme.push(action);
|
||||
action.action = 'attaque';
|
||||
action.data.dommagesReels = Number(action.data.dommages);
|
||||
action.data.niveau = compData.data.niveau;
|
||||
action.data.initiative = RdDCombatManager.calculInitiative(compData.data.niveau, carac[compData.data.defaut_carac].value);
|
||||
// Dupliquer les armes pouvant être à 1 main et 2 mains en patchant la compétence
|
||||
if (action.data.unemain && !action.data.deuxmains) {
|
||||
action.data.mainInfo = "(1m)";
|
||||
} else if (!action.data.unemain && action.data.deuxmains) {
|
||||
action.data.mainInfo = "(2m)";
|
||||
} else if (action.data.unemain && action.data.deuxmains) {
|
||||
action.data.mainInfo = "(1m)";
|
||||
|
||||
const comp2m = action.data.competence.replace(" 1 main", " 2 mains"); // Replace !
|
||||
const comp = Misc.data(competences.find(c => c.name == comp2m));
|
||||
|
||||
const arme2main = duplicate(action);
|
||||
arme2main.data.mainInfo = "(2m)";
|
||||
arme2main.data.niveau = comp.data.niveau;
|
||||
arme2main.data.competence = comp2m;
|
||||
arme2main.data.initiative = RdDCombatManager.calculInitiative(arme2main.data.niveau, carac[comp.data.defaut_carac].value);
|
||||
actionsArme.push(arme2main);
|
||||
const containsSlash = action.data.dommages.includes("/");
|
||||
if (containsSlash) {
|
||||
const tableauDegats = action.data.dommages.split("/");
|
||||
action.data.dommagesReels = Number(tableauDegats[0]);
|
||||
arme2main.data.dommagesReels = Number(tableauDegats[1]);
|
||||
}
|
||||
else {
|
||||
ui.notifications.info("Les dommages de l'arme à 1/2 mains " + action.name + " ne sont pas corrects (ie sous la forme X/Y)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return actions.sort(Misc.ascending(action => action.name + (action.system.infoMain ?? '')));
|
||||
}
|
||||
|
||||
static $prepareAttaqueArme(infoAttaque) {
|
||||
const comp = infoAttaque.competences.find(c => c.name == infoAttaque.competence);
|
||||
const attaque = duplicate(infoAttaque.arme);
|
||||
attaque.action = 'attaque';
|
||||
attaque.system.competence = infoAttaque.competence;
|
||||
attaque.system.dommagesReels = infoAttaque.dommagesReel;
|
||||
attaque.system.infoMain = infoAttaque.infoMain;
|
||||
attaque.system.niveau = comp.system.niveau;
|
||||
attaque.system.initiative = RdDCombatManager.calculInitiative(comp.system.niveau, infoAttaque.carac[comp.system.defaut_carac].value);
|
||||
return attaque;
|
||||
}
|
||||
|
||||
static listActionsCreature(competences) {
|
||||
return competences.filter(it => RdDItemCompetenceCreature.isCompetenceAttaque(it))
|
||||
.map(it => RdDItemCompetenceCreature.armeNaturelle(it));
|
||||
return actionsArme.sort(Misc.ascending(armeData => armeData.name + (armeData.data.mainInfo ?? '')));
|
||||
}
|
||||
|
||||
static listActionsPossessions(actor) {
|
||||
@ -230,9 +201,9 @@ export class RdDCombatManager extends Combat {
|
||||
return {
|
||||
name: p.name,
|
||||
action: 'conjurer',
|
||||
system: {
|
||||
data: {
|
||||
competence: p.name,
|
||||
possessionid: p.system.possessionid,
|
||||
possessionid: p.data.data.possessionid,
|
||||
}
|
||||
}
|
||||
}));
|
||||
@ -245,19 +216,21 @@ export class RdDCombatManager extends Combat {
|
||||
if (actions.length > 0) {
|
||||
return actions;
|
||||
}
|
||||
if (actor.isCreatureEntite()) {
|
||||
actions = actions.concat(RdDCombatManager.listActionsCreature(actor.itemTypes['competencecreature']));
|
||||
let items = actor.data.items;
|
||||
if (actor.isCreature()) {
|
||||
actions = actions.concat(items.filter(it => RdDItemCompetenceCreature.isCompetenceAttaque(it))
|
||||
.map(competence => RdDItemCompetenceCreature.toActionArme(competence)));
|
||||
} else {
|
||||
// Recupération des items 'arme'
|
||||
const armes = actor.itemTypes['arme'].filter(it => RdDItemArme.isArmeUtilisable(it))
|
||||
let armes = items.filter(it => RdDItemArme.isArmeUtilisable(it))
|
||||
//.concat(RdDItemArme.empoignade())
|
||||
.concat(RdDItemArme.mainsNues());
|
||||
|
||||
const competences = actor.itemTypes['competence'];
|
||||
actions = actions.concat(RdDCombatManager.listActionsArmes(armes, competences, actor.system.carac));
|
||||
let competences = items.filter(it => it.type == 'competence');
|
||||
actions = actions.concat(RdDCombatManager.listActionsArmes(armes, competences, actor.data.data.carac));
|
||||
|
||||
if (actor.system.attributs.hautrevant.value) {
|
||||
actions.push({ name: "Draconic", action: 'haut-reve', system: { initOnly: true, competence: "Draconic" } });
|
||||
if (actor.data.data.attributs.hautrevant.value) {
|
||||
actions.push({ name: "Draconic", action: 'haut-reve', data: { initOnly: true, competence: "Draconic" } });
|
||||
}
|
||||
}
|
||||
|
||||
@ -275,14 +248,14 @@ export class RdDCombatManager extends Combat {
|
||||
static processPremierRoundInit() {
|
||||
// Check if we have the whole init !
|
||||
if (Misc.isUniqueConnectedGM() && game.combat.current.round == 1) {
|
||||
let initMissing = game.combat.combatants.find(it => !it.initiative);
|
||||
let initMissing = game.combat.data.combatants.find(it => !it.initiative);
|
||||
if (!initMissing) { // Premier round !
|
||||
for (let combatant of game.combat.combatants) {
|
||||
for (let combatant of game.combat.data.combatants) {
|
||||
let action = combatant.initiativeData?.arme;
|
||||
//console.log("Parsed !!!", combatant, initDone, game.combat.current, arme);
|
||||
if (action && action.type == "arme") {
|
||||
for (let initData of premierRoundInit) {
|
||||
if (Grammar.toLowerCaseNoAccentNoSpace(action.system.initpremierround).includes(initData.pattern)) {
|
||||
if (Grammar.toLowerCaseNoAccentNoSpace(action.data.initpremierround).includes(initData.pattern)) {
|
||||
let msg = `<h4>L'initiative de ${combatant.actor.name} a été modifiée !</h4>
|
||||
<hr>
|
||||
<div>
|
||||
@ -353,16 +326,22 @@ export class RdDCombatManager extends Combat {
|
||||
initOffset = 9;
|
||||
initInfo = "Draconic"
|
||||
} else {
|
||||
compData = RdDItemCompetence.findCompetence(combatant.actor.items, action.system.competence);
|
||||
compNiveau = compData.system.niveau;
|
||||
initInfo = action.name + " / " + action.system.competence;
|
||||
compData = Misc.data(RdDItemCompetence.findCompetence(combatant.actor.data.items, action.data.competence));
|
||||
compNiveau = compData.data.niveau;
|
||||
initInfo = action.name + " / " + action.data.competence;
|
||||
|
||||
if (combatant.actor.type == 'creature' || combatant.actor.type == 'entite') {
|
||||
caracForInit = compData.system.carac_value;
|
||||
if (combatant.actor.data.type == 'creature' || combatant.actor.data.type == 'entite') {
|
||||
caracForInit = compData.data.carac_value;
|
||||
if (compData.data.categorie == "lancer") {
|
||||
initOffset = 7;
|
||||
}
|
||||
else {
|
||||
initOffset = 5;
|
||||
}
|
||||
} else {
|
||||
caracForInit = combatant.actor.system.carac[compData.system.defaut_carac].value;
|
||||
caracForInit = Misc.data(combatant.actor).data.carac[compData.data.defaut_carac].value;
|
||||
initOffset = RdDCombatManager._baseInitOffset(compData.data.categorie, action);
|
||||
}
|
||||
initOffset = RdDCombatManager._baseInitOffset(compData.system.categorie, action);
|
||||
}
|
||||
|
||||
let malus = combatant.actor.getEtatGeneral(); // Prise en compte état général
|
||||
@ -373,7 +352,6 @@ export class RdDCombatManager extends Combat {
|
||||
game.combat.rollInitiative(combatantId, rollFormula, { initInfo: initInfo });
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static _baseInitOffset(categorie, arme) {
|
||||
if (categorie == "tir") { // Offset de principe pour les armes de jet
|
||||
return 8;
|
||||
@ -381,12 +359,10 @@ export class RdDCombatManager extends Combat {
|
||||
if (categorie == "lancer") { // Offset de principe pour les armes de jet
|
||||
return 7;
|
||||
}
|
||||
switch (arme.system.cac) {
|
||||
case "empoignade":
|
||||
return 3;
|
||||
case "pugilat":
|
||||
case "naturelle":
|
||||
return 4;
|
||||
// Offset de principe pour les armes de jet
|
||||
switch (arme.data.cac) {
|
||||
case "empoignade": return 3;
|
||||
case "pugilat": return 4;
|
||||
}
|
||||
return 5;
|
||||
}
|
||||
@ -407,7 +383,7 @@ export class RdDCombatManager extends Combat {
|
||||
let menuItems = [];
|
||||
for (let action of actions) {
|
||||
menuItems.push({
|
||||
name: action.system.competence,
|
||||
name: action.data.competence,
|
||||
icon: "<i class='fas fa-dice-d6'></i>",
|
||||
callback: target => { RdDCombatManager.rollInitiativeAction(combatantId, action) }
|
||||
});
|
||||
@ -438,7 +414,7 @@ export class RdDCombat {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static onUpdateCombat(combat, change, options, userId) {
|
||||
if (combat.round != 0 && combat.turns && combat.active) {
|
||||
if (combat.data.round != 0 && combat.turns && combat.data.active) {
|
||||
RdDCombat.combatNouveauTour(combat);
|
||||
}
|
||||
}
|
||||
@ -470,30 +446,49 @@ export class RdDCombat {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static rddCombatTarget(target, attacker) {
|
||||
const defender = target?.actor;
|
||||
const defenderTokenId = target?.id;
|
||||
static createUsingTarget(attacker) {
|
||||
const target = RdDCombat.getTarget();
|
||||
if (target == undefined) {
|
||||
ui.notifications.warn((game.user.targets?.size ?? 0) > 1
|
||||
? "Vous devez choisir <strong>une seule</strong> cible à attaquer!"
|
||||
: "Vous devez choisir une cible à attaquer!");
|
||||
}
|
||||
else {
|
||||
const defender = target?.actor;
|
||||
const defenderTokenId = target?.data._id;
|
||||
if (defender.type == 'entite' && defender.data.data.definition.typeentite == ENTITE_NONINCARNE) {
|
||||
ui.notifications.warn("Vous ne pouvez pas cibler une entité non incarnée !!!!");
|
||||
} else {
|
||||
return this.create(attacker, defender, defenderTokenId, target)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getTarget() {
|
||||
if (game.user.targets && game.user.targets.size == 1) {
|
||||
for (let target of game.user.targets) {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static create(attacker, defender, defenderTokenId, target = undefined) {
|
||||
return new RdDCombat(attacker, defender, defenderTokenId, target)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static rddCombatForAttackerAndDefender(attackerId, defenderTokenId) {
|
||||
static createForAttackerAndDefender(attackerId, defenderTokenId) {
|
||||
const attacker = game.actors.get(attackerId);
|
||||
let defender = defenderTokenId ? canvas.tokens.get(defenderTokenId)?.actor : undefined;
|
||||
let target = undefined
|
||||
if (!defenderTokenId || !defender) {
|
||||
console.warn(`RdDCombat.rddCombatForAttackerAndDefender: appel avec defenderTokenId ${defenderTokenId} incorrect, ou pas de defender correspondant`);
|
||||
target = Targets.getTarget()
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
defenderTokenId = target.id;
|
||||
defender = target.actor;
|
||||
if (!defenderTokenId || !defender) {
|
||||
return;
|
||||
}
|
||||
if (defenderTokenId) {
|
||||
const defenderToken = canvas.tokens.get(defenderTokenId);
|
||||
const defender = defenderToken.actor;
|
||||
|
||||
return RdDCombat.create(attacker, defender, defenderTokenId);
|
||||
}
|
||||
return new RdDCombat(attacker, defender, defenderTokenId, target)
|
||||
return RdDCombat.createUsingTarget(attacker)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -501,10 +496,10 @@ export class RdDCombat {
|
||||
let defender = canvas.tokens.get(msg.defenderTokenId).actor;
|
||||
if (Misc.isOwnerPlayerOrUniqueConnectedGM()) {
|
||||
let attackerRoll = msg.attackerRoll;
|
||||
let attacker = msg.attackerId ? game.actors.get(msg.attackerId) : undefined;
|
||||
let attacker = msg.attackerId ? game.actors.get(msg.attackerId) : null;
|
||||
|
||||
defender.encaisserDommages(attackerRoll, attacker);
|
||||
const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.defenderTokenId);
|
||||
const rddCombat = RdDCombat.createForAttackerAndDefender(msg.attackerId, msg.defenderTokenId);
|
||||
rddCombat?.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
|
||||
}
|
||||
}
|
||||
@ -513,7 +508,7 @@ export class RdDCombat {
|
||||
static onMsgDefense(msg) {
|
||||
let defenderToken = canvas.tokens.get(msg.defenderTokenId);
|
||||
if (defenderToken && Misc.isUniqueConnectedGM()) {
|
||||
const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.defenderTokenId);
|
||||
const rddCombat = RdDCombat.createForAttackerAndDefender(msg.attackerId, msg.defenderTokenId);
|
||||
rddCombat?.removeChatMessageActionsPasseArme(msg.defenderRoll.passeArme);
|
||||
rddCombat?._chatMessageDefense(msg.paramChatDefense, msg.defenderRoll);
|
||||
}
|
||||
@ -540,10 +535,11 @@ export class RdDCombat {
|
||||
'#echec-total-attaque',
|
||||
]) {
|
||||
html.on("click", button, event => {
|
||||
const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(
|
||||
const rddCombat = RdDCombat.createForAttackerAndDefender(
|
||||
event.currentTarget.attributes['data-attackerId']?.value,
|
||||
event.currentTarget.attributes['data-defenderTokenId']?.value);
|
||||
if (rddCombat) {
|
||||
|
||||
rddCombat.onEvent(button, event);
|
||||
event.preventDefault();
|
||||
}
|
||||
@ -558,12 +554,12 @@ export class RdDCombat {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(attacker, defender, defenderTokenId, target) {
|
||||
this.attacker = attacker
|
||||
this.defender = defender
|
||||
this.target = target
|
||||
this.attackerId = this.attacker.id
|
||||
this.defenderId = this.defender.id
|
||||
this.defenderTokenId = defenderTokenId
|
||||
this.attacker = attacker;
|
||||
this.defender = defender;
|
||||
this.target = target;
|
||||
this.attackerId = this.attacker.data._id;
|
||||
this.defenderId = this.defender.data._id;
|
||||
this.defenderTokenId = defenderTokenId;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -689,87 +685,12 @@ export class RdDCombat {
|
||||
return rollData.rolled.isSuccess;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async proposerAjustementTirLancer(rollData) {
|
||||
if (['tir', 'lancer'].includes(rollData.competence.system.categorie)) {
|
||||
if (this.defender.isEntite([ENTITE_BLURETTE])) {
|
||||
ChatMessage.create({
|
||||
content: `<strong>La cible est une blurette, l'arme à distance sera perdue dans le blurêve`,
|
||||
whisper: ChatMessage.getWhisperRecipients("GM")
|
||||
})
|
||||
}
|
||||
else {
|
||||
const defenderToken = canvas.tokens.get(this.defenderTokenId);
|
||||
const dist = this.distance(_token, defenderToken)
|
||||
const isVisible = this.isVisible(_token, defenderToken)
|
||||
const portee = this._ajustementPortee(dist, rollData.arme)
|
||||
const taille = this._ajustementTaille(this.defender)
|
||||
const activite = this._ajustementMouvement(this.defender)
|
||||
const total = [portee, taille, activite].map(it => it.diff).filter(d => !Number.isNaN(d)).reduce(Misc.sum(), 0)
|
||||
ChatMessage.create({
|
||||
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-info-distance.html', {
|
||||
rollData: rollData,
|
||||
attacker: _token,
|
||||
isVisible: isVisible,
|
||||
defender: defenderToken,
|
||||
distance: dist,
|
||||
portee: portee,
|
||||
taille: taille,
|
||||
activite: activite,
|
||||
total: total
|
||||
}),
|
||||
whisper: ChatMessage.getWhisperRecipients("GM")
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isVisible(token, defenderToken) {
|
||||
return canvas.effects.visibility.testVisibility(defenderToken.center, { object: token })
|
||||
}
|
||||
|
||||
distance(token, defenderToken) {
|
||||
return Number(canvas.grid.measureDistances([{ ray: new Ray(token.center, defenderToken.center) }], { gridSpaces: false })).toFixed(1);
|
||||
}
|
||||
|
||||
_ajustementPortee(dist, arme) {
|
||||
if (dist <= arme.system.portee_courte) return { msg: "courte", diff: 0 };
|
||||
if (dist <= arme.system.portee_moyenne) return { msg: "moyenne", diff: -3 };
|
||||
if (dist <= arme.system.portee_extreme) return { msg: "extrême", diff: -5 };
|
||||
return { msg: "inatteignable", diff: -10 };
|
||||
}
|
||||
|
||||
_ajustementTaille(actor) {
|
||||
if (actor.isVehicule()) return { msg: "véhicule", diff: 0 }
|
||||
const taille = actor.getCaracByName('TAILLE')?.value ?? 1;
|
||||
if (taille <= 1) return { msg: "souris", diff: -8 };
|
||||
if (taille <= 3) return { msg: "chat", diff: -4 };
|
||||
if (taille <= 5) return { msg: "chien", diff: -2 };
|
||||
if (taille <= 15) return { msg: "humanoïde", diff: 0 };
|
||||
if (taille <= 20) return { msg: "ogre", diff: 2 };
|
||||
return { msg: "gigantesque", diff: 4 };
|
||||
}
|
||||
_ajustementMouvement(defender) {
|
||||
if (defender.getSurprise(true)) return { msg: "immobile (surprise)", diff: 0 };
|
||||
if (game.combat?.combatants.find(it => it.actorId == defender.id)) return { msg: "en mouvement (combat)", diff: -4 };
|
||||
return { msg: "à déterminer (0 immobile, -3 actif, -4 en mouvement, -5 en zig-zag)", diff: -3 };
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async attaque(competence, arme) {
|
||||
// const nonIncarnee = this.defender.isEntite([ENTITE_NONINCARNE])
|
||||
// const blurette = this.defender.isEntite([ENTITE_BLURETTE])
|
||||
// if (nonIncarnee || blurette) {
|
||||
// ChatMessage.create( {
|
||||
// content: `<strong>La cible est ${nonIncarnee ? 'non incarnée' : 'une blurette'}.
|
||||
// Il est impossible de l'atteindre.`,
|
||||
// whisper: ChatMessage.getWhisperRecipients("GM")})
|
||||
// }
|
||||
|
||||
if (!await this.attacker.accorder(this.defender, 'avant-attaque')) {
|
||||
if (!await this.accorderEntite('avant-attaque')) {
|
||||
return;
|
||||
}
|
||||
if (arme.system.cac == 'empoignade' && this.attacker.isCombatTouche()) {
|
||||
if (arme.data.cac == 'empoignade' && this.attacker.isCombatTouche()) {
|
||||
ChatMessage.create({
|
||||
alias: this.attacker.name,
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.attacker.name),
|
||||
@ -786,24 +707,25 @@ export class RdDCombat {
|
||||
if (arme) {
|
||||
this.attacker.verifierForceMin(arme);
|
||||
}
|
||||
await this.proposerAjustementTirLancer(rollData)
|
||||
|
||||
const dialog = await RdDRoll.create(this.attacker, rollData,
|
||||
{ html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html' },
|
||||
{
|
||||
name: 'jet-attaque',
|
||||
label: 'Attaque: ' + (arme?.name ?? competence.name),
|
||||
callbacks: [
|
||||
this.attacker.createCallbackExperience(),
|
||||
this.attacker.createCallbackAppelAuMoral(),
|
||||
{ action: r => this.removeChatMessageActionsPasseArme(r.passeArme) },
|
||||
{ condition: r => arme && !RdDCombat.isParticuliere(r), action: r => this.attacker.incDecItemUse(arme._id) },
|
||||
{ condition: r => (RdDCombat.isReussite(r) && !RdDCombat.isParticuliere(r)), action: r => this._onAttaqueNormale(r) },
|
||||
{ condition: RdDCombat.isParticuliere, action: r => this._onAttaqueParticuliere(r) },
|
||||
{ condition: RdDCombat.isEchec, action: r => this._onAttaqueEchec(r) },
|
||||
{ condition: RdDCombat.isEchecTotal, action: r => this._onAttaqueEchecTotal(r) },
|
||||
]
|
||||
});
|
||||
html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html',
|
||||
options: { height: 540 }
|
||||
}, {
|
||||
name: 'jet-attaque',
|
||||
label: 'Attaque: ' + (arme?.name ?? competence.name),
|
||||
callbacks: [
|
||||
this.attacker.createCallbackExperience(),
|
||||
this.attacker.createCallbackAppelAuMoral(),
|
||||
{ action: r => this.removeChatMessageActionsPasseArme(r.passeArme) },
|
||||
{ condition: r => arme && !RdDCombat.isParticuliere(r), action: r => this.attacker.incDecItemUse(arme._id) },
|
||||
{ condition: r => (RdDCombat.isReussite(r) && !RdDCombat.isParticuliere(r)), action: r => this._onAttaqueNormale(r) },
|
||||
{ condition: RdDCombat.isParticuliere, action: r => this._onAttaqueParticuliere(r) },
|
||||
{ condition: RdDCombat.isEchec, action: r => this._onAttaqueEchec(r) },
|
||||
{ condition: RdDCombat.isEchecTotal, action: r => this._onAttaqueEchecTotal(r) },
|
||||
]
|
||||
});
|
||||
dialog.render(true);
|
||||
}
|
||||
|
||||
@ -811,16 +733,15 @@ export class RdDCombat {
|
||||
_prepareAttaque(competence, arme) {
|
||||
let rollData = {
|
||||
passeArme: randomID(16),
|
||||
mortalite: arme?.system.mortalite,
|
||||
mortalite: arme?.data.mortalite,
|
||||
coupsNonMortels: false,
|
||||
competence: competence,
|
||||
surprise: this.attacker.getSurprise(true),
|
||||
surpriseDefenseur: this.defender.getSurprise(true),
|
||||
targetToken: Targets.extractTokenData(this.target),
|
||||
essais: {}
|
||||
};
|
||||
|
||||
if (this.attacker.isCreatureEntite()) {
|
||||
if (this.attacker.isCreature()) {
|
||||
RdDItemCompetenceCreature.setRollDataCreature(rollData);
|
||||
}
|
||||
else if (arme) {
|
||||
@ -829,8 +750,8 @@ export class RdDCombat {
|
||||
}
|
||||
else {
|
||||
// sans armes: à mains nues
|
||||
const niveau = competence.system.niveau;
|
||||
const init = RdDCombatManager.calculInitiative(niveau, this.attacker.system.carac['melee'].value);
|
||||
const niveau = competence.data.niveau;
|
||||
const init = RdDCombatManager.calculInitiative(niveau, Misc.templateData(this.attacker).carac['melee'].value);
|
||||
rollData.arme = RdDItemArme.mainsNues({ niveau: niveau, initiative: init });
|
||||
}
|
||||
return rollData;
|
||||
@ -843,9 +764,9 @@ export class RdDCombat {
|
||||
// force toujours, sauf empoignade
|
||||
// finesse seulement en mélée, pour l'empoignade, ou si la difficulté libre est de -1 minimum
|
||||
// rapidité seulement en mêlée, si l'arme le permet, et si la difficulté libre est de -1 minimum
|
||||
const isForce = !rollData.arme.system.empoignade;
|
||||
const isFinesse = rollData.arme.system.empoignade || isMeleeDiffNegative;
|
||||
const isRapide = !rollData.arme.system.empoignade && isMeleeDiffNegative && rollData.arme.system.rapide;
|
||||
const isForce = !rollData.arme.data.empoignade;
|
||||
const isFinesse = rollData.arme.data.empoignade || isMeleeDiffNegative;
|
||||
const isRapide = !rollData.arme.data.empoignade && isMeleeDiffNegative && rollData.arme.data.rapide;
|
||||
// si un seul choix possible, le prendre
|
||||
if (isForce && !isFinesse && !isRapide) {
|
||||
return await this.choixParticuliere(rollData, "force");
|
||||
@ -880,12 +801,12 @@ export class RdDCombat {
|
||||
attackerRoll.dmg = RdDBonus.dmg(attackerRoll, this.attacker.getBonusDegat(), this.defender.isEntite());
|
||||
let defenderRoll = { attackerRoll: attackerRoll, passeArme: attackerRoll.passeArme, show: {} }
|
||||
attackerRoll.show = {
|
||||
cible: this.target ? this.defender.name : 'la cible',
|
||||
cible: this.target ? this.defender.data.name : 'la cible',
|
||||
isRecul: (attackerRoll.particuliere == 'force' || attackerRoll.tactique == 'charge')
|
||||
}
|
||||
await RdDResolutionTable.displayRollData(attackerRoll, this.attacker, 'chat-resultat-attaque.html');
|
||||
|
||||
if (!await this.attacker.accorder(this.defender, 'avant-defense')) {
|
||||
if (!await this.accorderEntite('avant-defense')) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -901,7 +822,7 @@ export class RdDCombat {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async _sendMessageDefense(attackerRoll, defenderRoll, essaisPrecedents = undefined) {
|
||||
console.log("RdDCombat._sendMessageDefense", attackerRoll, defenderRoll, essaisPrecedents, " / ", this.attacker, this.target, this.attackerId, attackerRoll.competence.system.categorie);
|
||||
console.log("RdDCombat._sendMessageDefense", attackerRoll, defenderRoll, essaisPrecedents, " / ", this.attacker, this.target, this.attackerId, attackerRoll.competence.data.categorie);
|
||||
|
||||
this.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
|
||||
if (essaisPrecedents) {
|
||||
@ -909,16 +830,16 @@ export class RdDCombat {
|
||||
}
|
||||
|
||||
// # utilisation esquive
|
||||
const corpsACorps = this.defender.getCompetence("Corps à corps", { onMessage: it => console.info(it, this.defender) });
|
||||
const esquives = duplicate(this.defender.getCompetences("esquive", { onMessage: it => console.info(it, this.defender) }))
|
||||
esquives.forEach(e => e.system.nbUsage = e?._id ? this.defender.getItemUse(e._id) : 0);
|
||||
const corpsACorps = Misc.data(this.defender.getCompetence("Corps à corps", { onMessage: it => console.info(it, this.defender) }));
|
||||
const esquives = duplicate(this.defender.getCompetences("esquive", { onMessage: it => console.info(it, this.defender) }).map(c => Misc.data(c)));
|
||||
esquives.forEach(e => e.usages = e?.id ? this.defender.getItemUse(e.id) : 0);
|
||||
|
||||
const paramChatDefense = {
|
||||
passeArme: attackerRoll.passeArme,
|
||||
essais: attackerRoll.essais,
|
||||
isPossession: this.isPossession(attackerRoll),
|
||||
defender: this.defender,
|
||||
attacker: this.attacker,
|
||||
defender: Misc.data(this.defender),
|
||||
attacker: Misc.data(this.attacker),
|
||||
attackerId: this.attackerId,
|
||||
esquives: esquives,
|
||||
defenderTokenId: this.defenderTokenId,
|
||||
@ -926,7 +847,7 @@ export class RdDCombat {
|
||||
armes: this._filterArmesParade(this.defender, attackerRoll.competence, attackerRoll.arme),
|
||||
diffLibre: attackerRoll.ajustements?.diffLibre?.value ?? 0,
|
||||
attaqueParticuliere: attackerRoll.particuliere,
|
||||
attaqueCategorie: attackerRoll.competence.system.categorie,
|
||||
attaqueCategorie: attackerRoll.competence.data.categorie,
|
||||
attaqueArme: attackerRoll.arme,
|
||||
surprise: this.defender.getSurprise(true),
|
||||
dmg: attackerRoll.dmg,
|
||||
@ -958,8 +879,8 @@ export class RdDCombat {
|
||||
// envoyer le message au destinataire
|
||||
game.socket.emit(SYSTEM_SOCKET_ID, {
|
||||
msg: "msg_defense", data: {
|
||||
attackerId: this.attacker?.id,
|
||||
defenderId: this.defender?.id,
|
||||
attackerId: this.attacker?.data._id,
|
||||
defenderId: this.defender?.data._id,
|
||||
defenderTokenId: this.defenderTokenId,
|
||||
defenderRoll: defenderRoll,
|
||||
paramChatDefense: paramChatDefense,
|
||||
@ -970,11 +891,13 @@ export class RdDCombat {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_filterArmesParade(defender, competence) {
|
||||
let items = defender.items.filter(it => RdDItemArme.isArmeUtilisable(it) || RdDItemCompetenceCreature.isCompetenceParade(it))
|
||||
let items = defender.data.items;
|
||||
items = items.filter(it => RdDItemArme.isArmeUtilisable(it) || RdDItemCompetenceCreature.isCompetenceParade(it))
|
||||
.map(Misc.data);
|
||||
for (let item of items) {
|
||||
item.system.nbUsage = defender.getItemUse(item.id); // Ajout du # d'utilisation ce round
|
||||
item.data.nbUsage = defender.getItemUse(item._id); // Ajout du # d'utilisation ce round
|
||||
}
|
||||
switch (competence.system.categorie) {
|
||||
switch (competence.data.categorie) {
|
||||
case 'tir':
|
||||
case 'lancer':
|
||||
return items.filter(item => RdDItemArme.getCategorieParade(item) == 'boucliers')
|
||||
@ -993,7 +916,7 @@ export class RdDCombat {
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.attacker.name),
|
||||
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-etotal.html', {
|
||||
attackerId: this.attackerId,
|
||||
attacker: this.attacker,
|
||||
attacker: Misc.data(this.attacker),
|
||||
defenderTokenId: this.defenderTokenId,
|
||||
essais: attackerRoll.essais
|
||||
})
|
||||
@ -1006,7 +929,7 @@ export class RdDCombat {
|
||||
console.log("RdDCombat._onEchecTotal >>>", rollData);
|
||||
|
||||
const arme = rollData.arme;
|
||||
const avecArme = !['', 'sans-armes', 'armes-naturelles'].includes(arme?.system.categorie_parade ?? '');
|
||||
const avecArme = !['', 'sans-armes', 'armes-naturelles'].includes(arme?.data.categorie_parade ?? '');
|
||||
const action = (rollData.attackerRoll ? (arme ? "la parade" : "l'esquive") : "l'attaque");
|
||||
ChatUtility.createChatWithRollMode(this.defender.name, {
|
||||
content: `<strong>Maladresse à ${action}!</strong> ` + await RdDRollTables.getMaladresse({ arme: avecArme })
|
||||
@ -1025,7 +948,7 @@ export class RdDCombat {
|
||||
console.log("RdDCombat.choixParticuliere >>>", rollData, choix);
|
||||
|
||||
if (choix != "rapidite") {
|
||||
this.attacker.incDecItemUse(rollData.arme.id);
|
||||
this.attacker.incDecItemUse(rollData.arme._id);
|
||||
}
|
||||
|
||||
this.removeChatMessageActionsPasseArme(rollData.passeArme);
|
||||
@ -1037,29 +960,31 @@ export class RdDCombat {
|
||||
async parade(attackerRoll, armeParadeId) {
|
||||
const arme = this.defender.getArmeParade(armeParadeId);
|
||||
console.log("RdDCombat.parade >>>", attackerRoll, armeParadeId, arme);
|
||||
const competence = arme?.system?.competence;
|
||||
const competence = Misc.templateData(arme)?.competence;
|
||||
if (competence == undefined) {
|
||||
console.error("Pas de compétence de parade associée à ", arme?.name, armeParadeId);
|
||||
console.error("Pas de compétence de parade associée à ", arme);
|
||||
return;
|
||||
}
|
||||
|
||||
let rollData = this._prepareParade(attackerRoll, arme, competence);
|
||||
|
||||
const dialog = await RdDRoll.create(this.defender, rollData,
|
||||
{ html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html' },
|
||||
{
|
||||
name: 'jet-parade',
|
||||
label: 'Parade: ' + (arme ? arme.name : rollData.competence.name),
|
||||
callbacks: [
|
||||
this.defender.createCallbackExperience(),
|
||||
this.defender.createCallbackAppelAuMoral(),
|
||||
{ action: r => this.removeChatMessageActionsPasseArme(r.passeArme) },
|
||||
{ condition: r => !RdDCombat.isParticuliere(r), action: r => this.defender.incDecItemUse(armeParadeId) },
|
||||
{ condition: RdDCombat.isReussite, action: r => this._onParadeNormale(r) },
|
||||
{ condition: RdDCombat.isParticuliere, action: r => this._onParadeParticuliere(r) },
|
||||
{ condition: RdDCombat.isEchec, action: r => this._onParadeEchec(r) },
|
||||
]
|
||||
});
|
||||
html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html',
|
||||
options: { height: 540 }
|
||||
}, {
|
||||
name: 'jet-parade',
|
||||
label: 'Parade: ' + (arme ? arme.name : rollData.competence.name),
|
||||
callbacks: [
|
||||
this.defender.createCallbackExperience(),
|
||||
this.defender.createCallbackAppelAuMoral(),
|
||||
{ action: r => this.removeChatMessageActionsPasseArme(r.passeArme) },
|
||||
{ condition: r => !RdDCombat.isParticuliere(r), action: r => this.defender.incDecItemUse(armeParadeId) },
|
||||
{ condition: RdDCombat.isReussite, action: r => this._onParadeNormale(r) },
|
||||
{ condition: RdDCombat.isParticuliere, action: r => this._onParadeParticuliere(r) },
|
||||
{ condition: RdDCombat.isEchec, action: r => this._onParadeEchec(r) },
|
||||
]
|
||||
});
|
||||
dialog.render(true);
|
||||
}
|
||||
|
||||
@ -1069,16 +994,16 @@ export class RdDCombat {
|
||||
passeArme: attackerRoll.passeArme,
|
||||
diffLibre: attackerRoll.diffLibre,
|
||||
attackerRoll: attackerRoll,
|
||||
competence: this.defender.getCompetence(competenceParade),
|
||||
competence: Misc.data(this.defender.getCompetence(competenceParade)),
|
||||
arme: armeParade,
|
||||
surprise: this.defender.getSurprise(true),
|
||||
needParadeSignificative: ReglesOptionelles.isUsing('categorieParade') && RdDItemArme.needParadeSignificative(attackerRoll.arme, armeParade),
|
||||
needResist: RdDItemArme.needArmeResist(attackerRoll.arme, armeParade),
|
||||
carac: this.defender.system.carac,
|
||||
carac: Misc.templateData(this.defender).carac,
|
||||
show: {}
|
||||
};
|
||||
|
||||
if (this.defender.isCreatureEntite()) {
|
||||
if (this.defender.isCreature()) {
|
||||
RdDItemCompetenceCreature.setRollDataCreature(defenderRoll);
|
||||
}
|
||||
|
||||
@ -1118,7 +1043,7 @@ export class RdDCombat {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async esquive(attackerRoll, compId, compName) {
|
||||
const esquive = this.defender.getCompetence(compId) ?? this.defender.getCompetence(compName)
|
||||
const esquive = Misc.data(this.defender.getCompetence(compId) ?? this.defender.getCompetence(compName));
|
||||
if (esquive == undefined) {
|
||||
ui.notifications.error(this.defender.name + " n'a pas de compétence " + compName);
|
||||
return;
|
||||
@ -1127,20 +1052,19 @@ export class RdDCombat {
|
||||
let rollData = this._prepareEsquive(attackerRoll, esquive);
|
||||
|
||||
const dialog = await RdDRoll.create(this.defender, rollData,
|
||||
{ html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html' },
|
||||
{
|
||||
name: 'jet-esquive',
|
||||
label: 'Esquiver',
|
||||
callbacks: [
|
||||
this.defender.createCallbackExperience(),
|
||||
this.defender.createCallbackAppelAuMoral(),
|
||||
{ condition: r => !RdDCombat.isParticuliere(r), action: r => this.defender.incDecItemUse(esquive._id) },
|
||||
{ action: r => this.removeChatMessageActionsPasseArme(r.passeArme) },
|
||||
{ condition: RdDCombat.isReussite, action: r => this._onEsquiveNormale(r) },
|
||||
{ condition: RdDCombat.isParticuliere, action: r => this._onEsquiveParticuliere(r) },
|
||||
{ condition: RdDCombat.isEchec, action: r => this._onEsquiveEchec(r) },
|
||||
]
|
||||
});
|
||||
{ html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html' }, {
|
||||
name: 'jet-esquive',
|
||||
label: 'Esquiver',
|
||||
callbacks: [
|
||||
this.defender.createCallbackExperience(),
|
||||
this.defender.createCallbackAppelAuMoral(),
|
||||
{ condition: r => !RdDCombat.isParticuliere(r), action: r => this.defender.incDecItemUse(esquive._id) },
|
||||
{ action: r => this.removeChatMessageActionsPasseArme(r.passeArme) },
|
||||
{ condition: RdDCombat.isReussite, action: r => this._onEsquiveNormale(r) },
|
||||
{ condition: RdDCombat.isParticuliere, action: r => this._onEsquiveParticuliere(r) },
|
||||
{ condition: RdDCombat.isEchec, action: r => this._onEsquiveEchec(r) },
|
||||
]
|
||||
});
|
||||
dialog.render(true);
|
||||
}
|
||||
|
||||
@ -1153,11 +1077,11 @@ export class RdDCombat {
|
||||
competence: competence,
|
||||
surprise: this.defender.getSurprise(true),
|
||||
surpriseDefenseur: this.defender.getSurprise(true),
|
||||
carac: this.defender.system.carac,
|
||||
carac: Misc.templateData(this.defender).carac,
|
||||
show: {}
|
||||
};
|
||||
|
||||
if (this.defender.isCreatureEntite()) {
|
||||
if (this.defender.isCreature()) {
|
||||
RdDItemCompetenceCreature.setRollDataCreature(rollData);
|
||||
}
|
||||
return rollData;
|
||||
@ -1203,11 +1127,11 @@ export class RdDCombat {
|
||||
|
||||
const dmg = attackerRoll.dmg.dmgArme + attackerRoll.dmg.dmgActor;
|
||||
let arme = defenderRoll.arme;
|
||||
let resistance = Misc.toInt(arme.system.resistance);
|
||||
if (arme.system.magique) {
|
||||
let resistance = Misc.toInt(arme.data.resistance);
|
||||
if (arme.data.magique) {
|
||||
defenderRoll.show.deteriorationArme = 'resiste'; // Par défaut
|
||||
if (arme.system.resistance_magique == undefined) arme.system.resistance_magique = 0; // Quick fix
|
||||
if (dmg > arme.system.resistance_magique) { // Jet uniquement si dommages supérieur à résistance magique (cf. 274)
|
||||
if (arme.data.resistance_magique == undefined) arme.data.resistance_magique = 0; // Quick fix
|
||||
if (dmg > arme.data.resistance_magique) { // Jet uniquement si dommages supérieur à résistance magique (cf. 274)
|
||||
// Jet de résistance de l'arme de parade (p.132)
|
||||
let resistRoll = await RdDResolutionTable.rollData({
|
||||
caracValue: resistance,
|
||||
@ -1215,11 +1139,11 @@ export class RdDCombat {
|
||||
showDice: HIDE_DICE
|
||||
});
|
||||
if (!resistRoll.rolled.isSuccess) {
|
||||
let perteResistance = (dmg - arme.system.resistance_magique)
|
||||
let perteResistance = (dmg - arme.data.resistance_magique)
|
||||
resistance -= perteResistance;
|
||||
defenderRoll.show.deteriorationArme = resistance <= 0 ? 'brise' : 'perte';
|
||||
defenderRoll.show.perteResistance = perteResistance;
|
||||
this.defender.updateEmbeddedDocuments('Item', [{ _id: defenderRoll.arme._id, 'system.resistance': resistance }]);
|
||||
this.defender.updateEmbeddedDocuments('Item', [{ _id: defenderRoll.arme._id, 'data.resistance': resistance }]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -1235,14 +1159,14 @@ export class RdDCombat {
|
||||
resistance -= dmg;
|
||||
defenderRoll.show.deteriorationArme = resistance <= 0 ? 'brise' : 'perte';
|
||||
defenderRoll.show.perteResistance = dmg;
|
||||
this.defender.updateEmbeddedDocuments('Item', [{ _id: defenderRoll.arme._id, 'system.resistance': resistance }]);
|
||||
this.defender.updateEmbeddedDocuments('Item', [{ _id: defenderRoll.arme._id, 'data.resistance': resistance }]);
|
||||
}
|
||||
}
|
||||
// Si l'arme de parade n'est pas un bouclier, jet de désarmement (p.132)
|
||||
if (ReglesOptionelles.isUsing('defenseurDesarme') && resistance > 0 && RdDItemArme.getCategorieParade(defenderRoll.arme) != 'boucliers') {
|
||||
let desarme = await RdDResolutionTable.rollData({
|
||||
caracValue: this.defender.getForce(),
|
||||
finalLevel: Misc.toInt(defenderRoll.competence.system.niveau) - dmg,
|
||||
finalLevel: Misc.toInt(defenderRoll.competence.data.niveau) - dmg,
|
||||
showDice: HIDE_DICE
|
||||
});
|
||||
defenderRoll.show.desarme = desarme.rolled.isEchec;
|
||||
@ -1261,7 +1185,7 @@ export class RdDCombat {
|
||||
defenderRoll.show.recul = 'encaisse';
|
||||
} else if (rollRecul.rolled.isETotal || this._isReculCauseChute(impact)) {
|
||||
defenderRoll.show.recul = 'chute';
|
||||
await this.defender.setEffect(STATUSES.StatusProne, true);
|
||||
await this.defender.setStatusEffect("EFFECT.StatusProne", true);
|
||||
}
|
||||
else {
|
||||
defenderRoll.show.recul = 'recul';
|
||||
@ -1285,7 +1209,7 @@ export class RdDCombat {
|
||||
_computeImpactRecul(attaque) {
|
||||
const taille = this.defender.getTaille();
|
||||
const force = this.attacker.getForce();
|
||||
const dommages = attaque.arme.system.dommagesReels ?? attaque.arme.system.dommages;
|
||||
const dommages = attaque.arme.data.dommagesReels ?? attaque.arme.data.dommages;
|
||||
return taille - (force + dommages);
|
||||
}
|
||||
|
||||
@ -1303,7 +1227,7 @@ export class RdDCombat {
|
||||
attackerRoll.defenderTokenId = defenderTokenId;
|
||||
|
||||
await this.computeRecul(defenderRoll);
|
||||
this.defender.encaisserDommages(attackerRoll, this.attacker, defenderRoll?.show);
|
||||
this.defender.encaisserDommages(attackerRoll, this.attacker, defenderRoll);
|
||||
}
|
||||
else { // envoi à un GM: les joueurs n'ont pas le droit de modifier les personnages qu'ils ne possèdent pas
|
||||
game.socket.emit(SYSTEM_SOCKET_ID, {
|
||||
@ -1318,27 +1242,58 @@ export class RdDCombat {
|
||||
this.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* retourne true si on peut continuer, false si on ne peut pas continuer */
|
||||
async accorderEntite(when = 'avant-encaissement') {
|
||||
console.log("TETETET", game.settings.get(SYSTEM_RDD, "accorder-entite-cauchemar"), this.defender.isEntite([ENTITE_INCARNE]), this.defender.isEntiteAccordee(this.attacker))
|
||||
|
||||
if (when != game.settings.get(SYSTEM_RDD, "accorder-entite-cauchemar")
|
||||
|| this.defender == undefined
|
||||
|| !this.defender.isEntite([ENTITE_INCARNE])
|
||||
|| this.defender.isEntiteAccordee(this.attacker)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
let rolled = await RdDResolutionTable.roll(this.attacker.getReveActuel(), - Number(Misc.templateData(this.defender).carac.niveau.value));
|
||||
|
||||
let message = {
|
||||
content: "Jet de points actuels de rêve à " + rolled.finalLevel + RdDResolutionTable.explain(rolled) + "<br>",
|
||||
whisper: ChatMessage.getWhisperRecipients(this.attacker.name)
|
||||
};
|
||||
|
||||
if (rolled.isSuccess) {
|
||||
await this.defender.setEntiteReveAccordee(this.attacker);
|
||||
message.content += this.attacker.name + " s'est accordé avec " + this.defender.name;
|
||||
}
|
||||
else {
|
||||
message.content += this.attacker.name + " n'est pas accordé avec " + this.defender.name;
|
||||
}
|
||||
|
||||
ChatMessage.create(message);
|
||||
return rolled.isSuccess;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async displayActorCombatStatus(combat, actor) {
|
||||
let formData = {
|
||||
let data = {
|
||||
combatId: combat._id,
|
||||
alias: actor.name,
|
||||
etatGeneral: actor.getEtatGeneral(),
|
||||
isSonne: actor.getSonne(),
|
||||
blessuresStatus: actor.computeResumeBlessure(),
|
||||
SConst: actor.getSConst(),
|
||||
actorId: actor.id,
|
||||
actorId: actor.data._id,
|
||||
isGrave: false,
|
||||
isCritique: false
|
||||
}
|
||||
if (actor.countBlessuresNonSoigneeByName("critiques") > 0) { // Pour éviter le cumul grave + critique
|
||||
formData.isCritique = true;
|
||||
data.isCritique = true;
|
||||
} else if (actor.countBlessuresNonSoigneeByName("graves") > 0) {
|
||||
formData.isGrave = true;
|
||||
data.isGrave = true;
|
||||
}
|
||||
|
||||
ChatUtility.createChatWithRollMode(actor.name, {
|
||||
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-actor-turn-summary.html`, formData)
|
||||
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-actor-turn-summary.html`, data)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
/* -------------------------------------------- */
|
||||
|
||||
import { DialogChronologie } from "./dialog-chronologie.js";
|
||||
import { DialogCreateSigneDraconique } from "./dialog-create-signedraconique.js";
|
||||
import { DialogStress } from "./dialog-stress.js";
|
||||
import { Grammar } from "./grammar.js";
|
||||
import { RdDItemCompetence } from "./item-competence.js";
|
||||
import { Misc } from "./misc.js";
|
||||
import { RdDCarac } from "./rdd-carac.js";
|
||||
@ -13,7 +13,7 @@ import { RdDResolutionTable } from "./rdd-resolution-table.js";
|
||||
import { RdDRollResolutionTable } from "./rdd-roll-resolution-table.js";
|
||||
import { RdDRollTables } from "./rdd-rolltables.js";
|
||||
import { RdDUtility } from "./rdd-utility.js";
|
||||
import { CompendiumTableHelpers } from "./settings/system-compendiums.js";
|
||||
import { TMRRencontres } from "./tmr-rencontres.js";
|
||||
import { TMRUtility } from "./tmr-utility.js";
|
||||
|
||||
const rddRollNumeric = /^(\d+)\s*([\+\-]?\d+)?\s*(s)?/;
|
||||
@ -22,100 +22,55 @@ const rddRollNumeric = /^(\d+)\s*([\+\-]?\d+)?\s*(s)?/;
|
||||
export class RdDCommands {
|
||||
|
||||
static init() {
|
||||
const rddCommands = new RdDCommands();
|
||||
if (!game.system.rdd.commands) {
|
||||
const rddCommands = new RdDCommands();
|
||||
rddCommands.registerCommand({ path: ["/aide"], func: (content, msg, params) => rddCommands.help(msg), descr: "Affiche l'aide pour toutes les commandes" });
|
||||
rddCommands.registerCommand({ path: ["/help"], func: (content, msg, params) => rddCommands.help(msg), descr: "Affiche l'aide pour toutes les commandes" });
|
||||
rddCommands.registerCommand({ path: ["/table", "queues"], func: (content, msg, params) => RdDRollTables.getQueue(true), descr: "Tire une Queue de Dragon" });
|
||||
rddCommands.registerCommand({ path: ["/table", "ideefixe"], func: (content, msg, params) => RdDRollTables.getIdeeFixe(true), descr: "Tire une Idée fixe" });
|
||||
rddCommands.registerCommand({ path: ["/table", "desir"], func: (content, msg, params) => RdDRollTables.getDesirLancinant(true), descr: "Tire un Désir Lancinant" });
|
||||
rddCommands.registerCommand({ path: ["/table", "ombre"], func: (content, msg, params) => RdDRollTables.getOmbre(true), descr: "Tire une Ombre de Dragon" });
|
||||
rddCommands.registerCommand({ path: ["/table", "tetehr"], func: (content, msg, params) => RdDRollTables.getTeteHR(true), descr: "Tire une Tête de Dragon pour Hauts Revants" });
|
||||
rddCommands.registerCommand({ path: ["/table", "tete"], func: (content, msg, params) => RdDRollTables.getTete(true), descr: "Tire une Tête de Dragon" });
|
||||
rddCommands.registerCommand({ path: ["/table", "souffle"], func: (content, msg, params) => RdDRollTables.getSouffle(true), descr: " Tire un Souffle de Dragon" });
|
||||
rddCommands.registerCommand({ path: ["/table", "comp"], func: (content, msg, params) => RdDRollTables.getCompetence(true), descr: "Tire une compétence au hasard" });
|
||||
rddCommands.registerCommand({ path: ["/table", "tarot"], func: (content, msg, params) => RdDRollTables.getTarot(true), descr: "Tire une carte du Tarot Draconique" });
|
||||
rddCommands.registerCommand({ path: ["/meteo"], func: (content, msg, params) => rddCommands.getMeteo(msg, params), descr: "Propose une météo marine" });
|
||||
rddCommands.registerCommand({ path: ["/nom"], func: (content, msg, params) => RdDNameGen.getName(msg, params), descr: "Génère un nom aléatoire" });
|
||||
|
||||
Hooks.on("chatMessage", (html, content, msg) => {
|
||||
if (content[0] == '/') {
|
||||
let regExp = /(\S+)/g;
|
||||
let commands = content.match(regExp);
|
||||
if (rddCommands.processChatCommand(commands, content, msg)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
game.system.rdd.commands = rddCommands;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.commandsTable = undefined;
|
||||
}
|
||||
|
||||
_registerCommands() {
|
||||
this.commandsTable = {}
|
||||
this.registerCommand({ path: ["/aide"], func: (content, msg, params) => this.help(msg), descr: "Affiche l'aide pour toutes les commandes" });
|
||||
this.registerCommand({ path: ["/help"], func: (content, msg, params) => this.help(msg), descr: "Affiche l'aide pour toutes les commandes" });
|
||||
|
||||
this.registerCommand({ path: ["/liste", "comp"], func: (content, msg, params) => RdDRollTables.getCompetence('liste'), descr: "Affiche la liste des compétences" });
|
||||
|
||||
this.registerCommand({ path: ["/table", "queue"], func: (content, msg, params) => RdDRollTables.getQueue('liste'), descr: "Affiche la table des Queues de Dragon" });
|
||||
this.registerCommand({ path: ["/table", "ombre"], func: (content, msg, params) => RdDRollTables.getOmbre('liste'), descr: "Affiche la table des Ombres de Thanatos" });
|
||||
this.registerCommand({ path: ["/table", "tetehr"], func: (content, msg, params) => RdDRollTables.getTeteHR('liste'), descr: "Affiche la table des Têtes de Dragon pour Hauts Revants" });
|
||||
this.registerCommand({ path: ["/table", "tete"], func: (content, msg, params) => RdDRollTables.getTete('liste'), descr: "Affiche la table des Tête de Dragon pour tous" });
|
||||
this.registerCommand({ path: ["/table", "souffle"], func: (content, msg, params) => RdDRollTables.getSouffle('liste'), descr: "Affiche la table des Souffles de Dragon" });
|
||||
this.registerCommand({ path: ["/table", "tarot"], func: (content, msg, params) => RdDRollTables.getTarot('liste'), descr: "Affiche la table les cartes du Tarot Draconique" });
|
||||
this.registerCommand({ path: ["/table", "ideefixe"], func: (content, msg, params) => RdDRollTables.getIdeeFixe('liste'), descr: "Affiche la table des Idées fixes" });
|
||||
this.registerCommand({ path: ["/table", "desir"], func: (content, msg, params) => RdDRollTables.getDesirLancinant('liste'), descr: "Affiche la table des Désirs Lancinants" });
|
||||
this.registerCommand({
|
||||
path: ["/table", "rencontre"], func: (content, msg, params) => this.tableRencontres(msg, params),
|
||||
descr: `Affiche la table des Rencontres
|
||||
<br><strong>/table rencontre deso</strong> affiche la table des rencontres en Désolation
|
||||
<br><strong>/table rencontre mauvaise</strong> affiche la table des mauvaises rencontres`
|
||||
});
|
||||
this.registerCommand({ path: ["/table", "milieu"], func: (content, msg, params) => this.tableMilieu(msg, params, 'liste'), descr: "Affiche la table des ressource naturelles pour un milieu donné" });
|
||||
|
||||
this.registerCommand({ path: ["/tirer", "comp"], func: (content, msg, params) => RdDRollTables.getCompetence('chat'), descr: "Tire une compétence au hasard" });
|
||||
this.registerCommand({ path: ["/tirer", "queue"], func: (content, msg, params) => RdDRollTables.getQueue('chat'), descr: "Tire une Queue de Dragon" });
|
||||
this.registerCommand({ path: ["/tirer", "ombre"], func: (content, msg, params) => RdDRollTables.getOmbre('chat'), descr: "Tire une Ombre de Thanatos" });
|
||||
this.registerCommand({ path: ["/tirer", "tetehr"], func: (content, msg, params) => RdDRollTables.getTeteHR('chat'), descr: "Tire une Tête de Dragon pour Hauts Revants" });
|
||||
this.registerCommand({ path: ["/tirer", "tete"], func: (content, msg, params) => RdDRollTables.getTete('chat'), descr: "Tire une Tête de Dragon" });
|
||||
this.registerCommand({ path: ["/tirer", "souffle"], func: (content, msg, params) => RdDRollTables.getSouffle('chat'), descr: "Tire un Souffle de Dragon" });
|
||||
this.registerCommand({ path: ["/tirer", "tarot"], func: (content, msg, params) => RdDRollTables.getTarot('chat'), descr: "Tire une carte du Tarot Draconique" });
|
||||
this.registerCommand({ path: ["/tirer", "ideefixe"], func: (content, msg, params) => RdDRollTables.getIdeeFixe('chat'), descr: "Tire une Idée fixe" });
|
||||
this.registerCommand({ path: ["/tirer", "desir"], func: (content, msg, params) => RdDRollTables.getDesirLancinant('chat'), descr: "Tire un Désir Lancinant" });
|
||||
this.registerCommand({ path: ["/tirer", "rencontre"], func: (content, msg, params) => this.getRencontreTMR(params), descr: `Détermine une rencontre dans les TMR (synonyme de "/tmrr")` });
|
||||
this.registerCommand({ path: ["/tirer", "milieu"], func: (content, msg, params) => this.tableMilieu(msg, params, 'chat'), descr: "Effectue un tirage dans la table desressource naturelles pour un milieu donné" });
|
||||
|
||||
this.registerCommand({ path: ["/meteo"], func: (content, msg, params) => this.getMeteo(msg, params), descr: "Propose une météo marine" });
|
||||
this.registerCommand({ path: ["/nom"], func: (content, msg, params) => RdDNameGen.getName(msg, params), descr: "Génère un nom aléatoire" });
|
||||
|
||||
this.registerCommand({
|
||||
path: ["/tmr"], func: (content, msg, params) => this.findTMR(msg, params),
|
||||
descr: `Cherche où se trouve une case des Terres médianes
|
||||
<br><strong>/tmr sord</strong> indique que la cité Sordide est en D13
|
||||
<br><strong>/tmr foret</strong> donne la liste des TMR dont le nom contient "foret" (donc, toutes les forêts)`
|
||||
});
|
||||
this.registerCommand({
|
||||
path: ["/tmra"], func: (content, msg, params) => this.getTMRAleatoire(msg, params),
|
||||
descr: `Tire une case aléatoire des Terres médianes
|
||||
rddCommands.registerCommand({
|
||||
path: ["/tmra"], func: (content, msg, params) => rddCommands.getTMRAleatoire(msg, params),
|
||||
descr: `Tire une case aléatoire des Terres médianes
|
||||
<br><strong>/tmra forêt</strong> détermine une 'forêt' aléatoire
|
||||
<br><strong>/tmra</strong> détermine une case aléatoire dans toutes les TMR`
|
||||
});
|
||||
this.registerCommand({
|
||||
path: ["/tmrr"], func: (content, msg, params) => this.getRencontreTMR(params),
|
||||
descr: `Détermine une rencontre dans les TMR
|
||||
<br><strong>/tmrr forêt</strong> détermine une rencontre aléatoire en 'forêt'
|
||||
<br><strong>/tmrr mauvaise</strong> détermine une mauvaise rencontre aléatoire
|
||||
<br><strong>/tmrr for 47</strong> détermine la rencontre en 'forêt' pour un jet de dé de 47`
|
||||
});
|
||||
<br><strong>/tmra</strong> détermine une case aléatoire dans toutes les TMR` });
|
||||
rddCommands.registerCommand({
|
||||
path: ["/tmr"], func: (content, msg, params) => rddCommands.findTMR(msg, params),
|
||||
descr: `Cherche où se trouve une case des Terres médianes
|
||||
<br><strong>/tmr? sordide</strong> indique que la cité Sordide est en D13
|
||||
<br><strong>/tmr? foret</strong> donne la liste des TMR dont le nom contient "foret" (donc, toutes les forêts)` });
|
||||
rddCommands.registerCommand({
|
||||
path: ["/tmrr"], func: (content, msg, params) => rddCommands.getRencontreTMR(params),
|
||||
descr: `Détermine une rencontre dans un type de case
|
||||
<br><strong>/tmrr foret</strong> lance un d100 et détermine la rencontre correspondante en 'forêt'
|
||||
<br><strong>/tmrr forêt 47</strong> détermine la rencontre en 'forêt' pour un jet de dé de 47`
|
||||
});
|
||||
|
||||
this.registerCommand({
|
||||
path: ["/xp", "comp"], func: (content, msg, params) => this.getCoutXpComp(msg, params),
|
||||
descr: `Détermine le coût d'expérience pour augmenter une compétence. Exemples:
|
||||
rddCommands.registerCommand({
|
||||
path: ["/xp", "comp"], func: (content, msg, params) => rddCommands.getCoutXpComp(msg, params),
|
||||
descr: `Détermine le coût d'expérience pour augmenter une compétence. Exemples:
|
||||
<br>/xp comp -6 1: pour passer de -6 à +1
|
||||
<br>/xp comp +4: pour atteindre le niveau 4 (depuis +3)`
|
||||
});
|
||||
});
|
||||
|
||||
this.registerCommand({
|
||||
path: ["/xp", "carac"], func: (content, msg, params) => this.getCoutXpCarac(msg, params),
|
||||
descr: `Détermine le coût d'expérience pour augmenter une caractéristique. Exemples:
|
||||
rddCommands.registerCommand({
|
||||
path: ["/xp", "carac"], func: (content, msg, params) => rddCommands.getCoutXpCarac(msg, params),
|
||||
descr: `Détermine le coût d'expérience pour augmenter une caractéristique. Exemples:
|
||||
<br>/xp carac 15: coût pour atteindre 15 (depuis 14)`
|
||||
});
|
||||
});
|
||||
|
||||
this.registerCommand({
|
||||
path: ["/rdd"], func: (content, msg, params) => this.rollRdd(msg, params),
|
||||
descr: `Effectue un jet de dés dans la table de résolution. Exemples:
|
||||
rddCommands.registerCommand({
|
||||
path: ["/rdd"], func: (content, msg, params) => rddCommands.rollRdd(msg, params),
|
||||
descr: `Effectue un jet de dés dans la table de résolution. Exemples:
|
||||
<br><strong>/rdd</strong> ouvre la table de résolution
|
||||
<br><strong>/rdd 10 3</strong> effectue un jet 10 à +3
|
||||
<br><strong>/rdd 15 -2</strong> effectue un jet 15 à -2
|
||||
@ -123,46 +78,47 @@ export class RdDCommands {
|
||||
<br><strong>/rdd Vue Vigilance -2</strong> effectue un jet de Vue/Vigilance à -2 pour les tokens sélectionnés
|
||||
<br><strong>/rdd vol déser +2</strong> effectue un jet de Volonté/Survie en désert à +2 pour les tokens sélectionnés
|
||||
`
|
||||
});
|
||||
this.registerCommand({ path: ["/ddr"], func: (content, msg, params) => this.rollDeDraconique(msg), descr: "Lance un Dé Draconique" });
|
||||
});
|
||||
rddCommands.registerCommand({ path: ["/ddr"], func: (content, msg, params) => rddCommands.rollDeDraconique(msg), descr: "Lance un Dé Draconique" });
|
||||
|
||||
this.registerCommand({
|
||||
path: ["/payer"], func: (content, msg, params) => RdDUtility.afficherDemandePayer(params[0], params[1]),
|
||||
descr: `Demande aux joueurs de payer un montant. Exemples:
|
||||
rddCommands.registerCommand({
|
||||
path: ["/payer"], func: (content, msg, params) => RdDUtility.afficherDemandePayer(params[0], params[1]),
|
||||
descr: `Permet de payer un montant. Exemples:
|
||||
<br><strong>/payer 5s 10d</strong> permet d'envoyer un message pour payer 5 sols et 10 deniers
|
||||
<br><strong>/payer 10d</strong> permet d'envoyer un message pour payer 10 deniers`
|
||||
});
|
||||
this.registerCommand({
|
||||
path: ["/astro"], func: (content, msg, params) => RdDUtility.afficherHeuresChanceMalchance(Misc.join(params, ' ')),
|
||||
descr: `Affiche les heures de chance et de malchance selon l'heure de naissance donnée en argument. Exemples pour l'heure de la Lyre:
|
||||
});
|
||||
rddCommands.registerCommand({
|
||||
path: ["/astro"], func: (content, msg, params) => RdDUtility.afficherHeuresChanceMalchance(Misc.join(params, ' ')),
|
||||
descr: `Affiche les heures de chance et de malchance selon l'heure de naissance donnée en argument. Exemples pour l'heure de la Lyre:
|
||||
<br><strong>/astro 7</strong>
|
||||
<br><strong>/astro Lyre</strong>
|
||||
<br><strong>/astro Lyr</strong>`
|
||||
});
|
||||
});
|
||||
|
||||
this.registerCommand({
|
||||
path: ["/signe", "+"], func: (content, msg, params) => this.creerSignesDraconiques(),
|
||||
descr: "Crée un signe draconique et l'ajoute aux haut-rêvants choisis."
|
||||
});
|
||||
rddCommands.registerCommand({
|
||||
path: ["/signe", "+"], func: (content, msg, params) => rddCommands.creerSignesDraconiques(),
|
||||
descr: "Crée un signe draconique et l'ajoute aux haut-rêvants choisis."
|
||||
});
|
||||
|
||||
this.registerCommand({
|
||||
path: ["/signe", "-"], func: (content, msg, params) => this.supprimerSignesDraconiquesEphemeres(),
|
||||
descr: "Supprime les signes draconiques éphémères"
|
||||
});
|
||||
rddCommands.registerCommand({
|
||||
path: ["/signe", "-"], func: (content, msg, params) => rddCommands.supprimerSignesDraconiquesEphemeres(),
|
||||
descr: "Supprime les signes draconiques éphémères"
|
||||
});
|
||||
|
||||
this.registerCommand({
|
||||
path: ["/stress"], func: (content, msg, params) => this.distribuerStress(params),
|
||||
descr: `Distribue du stress aux personnages. Exemples:
|
||||
rddCommands.registerCommand({
|
||||
path: ["/stress"], func: (content, msg, params) => rddCommands.distribuerStress(params),
|
||||
descr: `Distribue du stress aux personnages. Exemples:
|
||||
<br><strong>/stress</strong> : Ouvre une fenêtre pour donner du stress ou de l'expérience à un ensemble de personnages
|
||||
<br><strong>/stress 6</strong> : Distribue 6 points des Stress à tout les personnages joueurs, sans raison renseignée
|
||||
<br><strong>/stress 6 Tigre</strong> : Distribue 6 points des Stress à tout les personnages joueurs, à cause d'un Tigre (Vert)
|
||||
<br><strong>/stress 6 Glou Paulo</strong> : Distribue 6 points de Stress au personnage Paulon ou au personnage joueur Paulo, à cause d'un Glou`
|
||||
});
|
||||
});
|
||||
|
||||
this.registerCommand({
|
||||
path: ["/chrono"], func: (content, msg, params) => DialogChronologie.create(),
|
||||
descr: `Enregistre une entrée de chronologie dans un article de journal`
|
||||
});
|
||||
game.system.rdd.commands = rddCommands;
|
||||
}
|
||||
}
|
||||
constructor() {
|
||||
this.commandsTable = {};
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -204,50 +160,37 @@ export class RdDCommands {
|
||||
processChatCommand(commandLine, content = '', msg = {}) {
|
||||
// Setup new message's visibility
|
||||
let rollMode = game.settings.get("core", "rollMode");
|
||||
if (["gmroll", "blindroll"].includes(rollMode)) {
|
||||
msg["whisper"] = ChatMessage.getWhisperRecipients("GM");
|
||||
}
|
||||
if (rollMode === "blindroll"){
|
||||
msg["blind"] = true;
|
||||
}
|
||||
if (["gmroll", "blindroll"].includes(rollMode)) msg["whisper"] = ChatMessage.getWhisperRecipients("GM");
|
||||
if (rollMode === "blindroll") msg["blind"] = true;
|
||||
msg["type"] = 0;
|
||||
|
||||
if (!this.commandsTable) {
|
||||
this._registerCommands();
|
||||
}
|
||||
|
||||
let command = commandLine[0].toLowerCase();
|
||||
if (this._isCommandHandled(command)) {
|
||||
let params = commandLine.slice(1);
|
||||
this._processCommand(this.commandsTable, command, params, content, msg);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
let params = commandLine.slice(1);
|
||||
|
||||
return this.process(command, params, content, msg);
|
||||
}
|
||||
|
||||
_isCommandHandled(command){
|
||||
return this.commandsTable[command] != undefined;
|
||||
process(command, params, content, msg) {
|
||||
return this._processCommand(this.commandsTable, command, params, content, msg);
|
||||
}
|
||||
|
||||
async _processCommand(commandsTable, name, params, content = '', msg = {}, path = "") {
|
||||
_processCommand(commandsTable, name, params, content = '', msg = {}, path = "") {
|
||||
let command = commandsTable[name];
|
||||
path = path + name + " ";
|
||||
if (command && command.subTable) {
|
||||
if (params[0]) {
|
||||
this._processCommand(command.subTable, params[0], params.slice(1), content, msg, path)
|
||||
return this._processCommand(command.subTable, params[0], params.slice(1), content, msg, path)
|
||||
}
|
||||
else {
|
||||
this.help(msg, command.subTable);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (command && command.func) {
|
||||
new Promise(async () => {
|
||||
const result = await command.func(content, msg, params);
|
||||
if (result == false) {
|
||||
RdDCommands._chatAnswer(msg, command.descr);
|
||||
}
|
||||
});
|
||||
const result = command.func(content, msg, params);
|
||||
if (result == false) {
|
||||
RdDCommands._chatAnswer(msg, command.descr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -258,10 +201,10 @@ export class RdDCommands {
|
||||
this.help(msg, undefined);
|
||||
}
|
||||
async help(msg, table) {
|
||||
let commands = []
|
||||
this._buildSubTableHelp(commands, table ?? this.commandsTable);
|
||||
let list = []
|
||||
this._buildSubTableHelp(list, table || this.commandsTable);
|
||||
|
||||
let html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/settings/dialog-aide-commands.html", { commands: commands });
|
||||
let html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/settings/dialog-aide-commands.html", { commands: list });
|
||||
let d = new Dialog(
|
||||
{
|
||||
title: "Commandes disponibles dans le tchat",
|
||||
@ -269,7 +212,7 @@ export class RdDCommands {
|
||||
buttons: {},
|
||||
},
|
||||
{
|
||||
width: 600, height: 600,
|
||||
width: 600, height: 500,
|
||||
});
|
||||
|
||||
d.render(true);
|
||||
@ -299,9 +242,11 @@ export class RdDCommands {
|
||||
/* -------------------------------------------- */
|
||||
async getRencontreTMR(params) {
|
||||
if (params.length == 1 || params.length == 2) {
|
||||
return game.system.rdd.rencontresTMR.rollRencontre(params[0], params[1])
|
||||
return TMRRencontres.rollRencontre(params[0], params[1])
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -331,7 +276,7 @@ export class RdDCommands {
|
||||
diff = 0;
|
||||
}
|
||||
const caracName = params[0];
|
||||
let competence = length > 1 ? actors[0].getCompetence(Misc.join(params.slice(1, length), ' ')) : {name:undefined};
|
||||
let competence = length > 1 ? actors[0].getCompetence(Misc.join(params.slice(1, length), ' ')) : undefined;
|
||||
if (competence) {
|
||||
for (let actor of actors) {
|
||||
await actor.rollCaracCompetence(caracName, competence.name, diff);
|
||||
@ -354,20 +299,20 @@ export class RdDCommands {
|
||||
show: { title: "Table de résolution" }
|
||||
};
|
||||
await RdDResolutionTable.rollData(rollData);
|
||||
return RdDCommands._chatAnswer(msg, await RdDResolutionTable.buildRollDataHtml(rollData));
|
||||
RdDCommands._chatAnswer(msg, await RdDResolutionTable.buildRollDataHtml(rollData));
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async rollDeDraconique(msg) {
|
||||
let ddr = await RdDDice.rollTotal("1dr + 7");
|
||||
return RdDCommands._chatAnswer(msg, `Lancer d'un Dé draconique: ${ddr}`);
|
||||
RdDCommands._chatAnswer(msg, `Lancer d'un Dé draconique: ${ddr}`);
|
||||
}
|
||||
|
||||
async getTMRAleatoire(msg, params) {
|
||||
if (params.length < 2) {
|
||||
let type = params[0];
|
||||
const tmr = await TMRUtility.getTMRAleatoire(type ? (it => it.type == type) : (it => true));
|
||||
return RdDCommands._chatAnswer(msg, `Case aléatoire: ${tmr.coord} - ${tmr.label}`);
|
||||
RdDCommands._chatAnswer(msg, `Case aléatoire: ${tmr.coord} - ${tmr.label}`);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
@ -375,61 +320,20 @@ export class RdDCommands {
|
||||
}
|
||||
|
||||
async findTMR(msg, params) {
|
||||
if (params && params.length > 0) {
|
||||
const search = Misc.join(params, ' ');
|
||||
const found = TMRUtility.findTMR(search);
|
||||
if (found?.length > 0) {
|
||||
return RdDCommands._chatAnswer(msg, `Les TMRs correspondant à '${search}' sont:` + Misc.join(found.map(it => `<br>${it.coord}: ${it.label}`)));
|
||||
}
|
||||
return RdDCommands._chatAnswer(msg, 'Aucune TMR correspondant à ' + search);
|
||||
const search = Misc.join(params, ' ');
|
||||
const found = TMRUtility.findTMR(search);
|
||||
if (found?.length > 0) {
|
||||
return RdDCommands._chatAnswer(msg, `Les TMRs correspondant à '${search}' sont:` + Misc.join(found.map(it => `<br>${it.coord}: ${it.label}`)));
|
||||
}
|
||||
return false;
|
||||
return RdDCommands._chatAnswer(msg, 'Aucune TMR correspondant à ' + search);
|
||||
}
|
||||
|
||||
async tableRencontres(msg, params) {
|
||||
if (params && params.length > 0) {
|
||||
const search = Misc.join(params, ' ');
|
||||
const solvedTerrain = TMRUtility.findTMRLike(search);
|
||||
if (solvedTerrain == undefined) {
|
||||
return RdDCommands._chatAnswer(msg, 'Aucune TMR correspondant à ' + search);
|
||||
}
|
||||
return await game.system.rdd.rencontresTMR.chatTable(solvedTerrain);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async tableMilieu(msg, params, toChat) {
|
||||
if (params && params.length > 0) {
|
||||
const search = Misc.join(params, ' ');
|
||||
const milieux = await game.system.rdd.environnement.findEnvironnementsLike(search);
|
||||
if (milieux.length == 0) {
|
||||
const tous = Object.values(await game.system.rdd.environnement.milieux());
|
||||
return RdDCommands._chatAnswer(msg, `<strong>Aucun milieu correspondant à '${search}'.</strong>
|
||||
<br>Milieux disponibles:
|
||||
<br><ul class="chat-list"><li>${tous.reduce(Misc.joining('</li><li>'))}</li></ul>`);
|
||||
}
|
||||
if (milieux.length > 1) {
|
||||
ui.notifications.warn(`<strong>Plusieurs milieux correspondent à '${search}'</strong>:
|
||||
<br><ul class="chat-list"><li>${milieux.reduce(Misc.joining('</li><li>'))}</li></ul>`);
|
||||
}
|
||||
const tableName = `ressources en ${milieux.reduce(Misc.joining(', '))}`;
|
||||
if (toChat == 'liste') {
|
||||
return await game.system.rdd.environnement.searchToChatMessage(milieux, tableName);
|
||||
}
|
||||
else {
|
||||
const row = await game.system.rdd.environnement.getRandom(milieux, tableName);
|
||||
await CompendiumTableHelpers.tableRowToChatMessage(row, 'Item');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getCoutXpComp(msg, params) {
|
||||
if (params && (params.length == 1 || params.length == 2)) {
|
||||
let to = params.length == 1 ? Number(params[0]) : Number(params[1]);
|
||||
let from = params.length == 1 ? to - 1 : Number(params[0]);
|
||||
return RdDCommands._chatAnswer(msg, `Coût pour passer une compétence de ${from} à ${to}: ${RdDItemCompetence.getDeltaXp(from, to)}`);
|
||||
RdDCommands._chatAnswer(msg, `Coût pour passer une compétence de ${from} à ${to}: ${RdDItemCompetence.getDeltaXp(from, to)}`);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
@ -440,7 +344,7 @@ export class RdDCommands {
|
||||
getCoutXpCarac(msg, params) {
|
||||
if (params && params.length == 1) {
|
||||
let to = Number(params[0]);
|
||||
return RdDCommands._chatAnswer(msg, `Coût pour passer une caractéristique de ${to - 1} à ${to}: ${RdDCarac.getCaracXp(to)}`);
|
||||
RdDCommands._chatAnswer(msg, `Coût pour passer une caractéristique de ${to - 1} à ${to}: ${RdDCarac.getCaracXp(to)}`);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
@ -454,9 +358,10 @@ export class RdDCommands {
|
||||
|
||||
async supprimerSignesDraconiquesEphemeres() {
|
||||
game.actors.forEach(actor => {
|
||||
const ephemeres = actor.items.filter(item => item.type = 'signedraconique' && item.system.ephemere);
|
||||
const ephemeres = actor.filterItems(item => Misc.data(item).type = 'signedraconique' && Misc.data(item).data.ephemere)
|
||||
.map(item => item.id);
|
||||
if (ephemeres.length > 0) {
|
||||
actor.deleteEmbeddedDocuments("Item", ephemeres.map(item => item.id));
|
||||
actor.deleteEmbeddedDocuments("Item", ephemeres);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
@ -500,6 +405,5 @@ export class RdDCommands {
|
||||
async getMeteo(msg, params) {
|
||||
return await RdDMeteo.getMeteo();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,13 @@
|
||||
import { SYSTEM_RDD } from "./constants.js";
|
||||
import { Misc } from "./misc.js";
|
||||
|
||||
export class RddCompendiumOrganiser {
|
||||
static init() {
|
||||
Hooks.on('renderCompendium', async (pack, html, compendiumData) => RddCompendiumOrganiser.onRenderCompendium(pack, html, compendiumData))
|
||||
Hooks.on('renderCompendium', async (pack, html, data) => RddCompendiumOrganiser.onRenderCompendium(pack, html, data))
|
||||
}
|
||||
|
||||
static async onRenderCompendium(compendium, html, compendiumData) {
|
||||
console.log('onRenderCompendium', compendium, html, compendiumData);
|
||||
static async onRenderCompendium(compendium, html, data) {
|
||||
console.log('onRenderCompendium', compendium, html, data);
|
||||
const pack = compendium.collection
|
||||
if (pack.metadata.system === SYSTEM_RDD) {
|
||||
html.find('.directory-item').each((i, element) => {
|
||||
@ -16,7 +17,7 @@ export class RddCompendiumOrganiser {
|
||||
}
|
||||
|
||||
static async setEntityTypeName(pack, element) {
|
||||
const label = RddCompendiumOrganiser.getEntityTypeLabel(await pack.getDocument(element.dataset.documentId));
|
||||
const label = Misc.getEntityTypeLabel(await pack.getDocument(element.dataset.documentId));
|
||||
RddCompendiumOrganiser.insertEntityType(element, label);
|
||||
}
|
||||
|
||||
@ -26,17 +27,4 @@ export class RddCompendiumOrganiser {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static getEntityTypeLabel(entity) {
|
||||
const documentName = entity?.documentName
|
||||
const type = entity?.type
|
||||
if (documentName === 'Actor' || documentName === 'Item') {
|
||||
const label = CONFIG[documentName]?.typeLabels?.[type] ?? type;
|
||||
if (game.i18n.has(label)) {
|
||||
return game.i18n.localize(label);
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
import { Grammar } from "./grammar.js";
|
||||
import { ReglesOptionelles } from "./settings/regles-optionelles.js";
|
||||
|
||||
export class RdDConfirm {
|
||||
/* -------------------------------------------- */
|
||||
static confirmer(options, autresActions) {
|
||||
options.bypass = options.bypass || !(options.settingConfirmer == undefined || ReglesOptionelles.isUsing(options.settingConfirmer));
|
||||
if (options.bypass) {
|
||||
options.onAction();
|
||||
}
|
||||
else {
|
||||
let buttons = {
|
||||
"action": RdDConfirm._createButtonAction(options),
|
||||
"cancel": RdDConfirm._createButtonCancel()
|
||||
};
|
||||
if (options.settingConfirmer) {
|
||||
buttons = mergeObject(RdDConfirm._createButtonActionSave(options), buttons);
|
||||
}
|
||||
if (autresActions) {
|
||||
buttons = mergeObject(autresActions, buttons);
|
||||
}
|
||||
const dialogDetails = {
|
||||
title: options.title,
|
||||
content: options.content,
|
||||
default: "cancel",
|
||||
buttons: buttons
|
||||
};
|
||||
new Dialog(dialogDetails, { width: 150 * Object.keys(buttons).length }).render(true);
|
||||
}
|
||||
}
|
||||
|
||||
static _createButtonCancel() {
|
||||
return { icon: '<i class="fas fa-times"></i>', label: "Annuler" };
|
||||
}
|
||||
|
||||
static _createButtonAction(options) {
|
||||
return {
|
||||
icon: '<i class="fas fa-check"></i>',
|
||||
label: options.buttonLabel,
|
||||
callback: () => options.onAction()
|
||||
};
|
||||
}
|
||||
|
||||
static _createButtonActionSave(options) {
|
||||
return {
|
||||
"actionSave": {
|
||||
icon: '<i class="fas fa-user-check"></i>',
|
||||
label: options.buttonLabel + "<br>et ne plus demander",
|
||||
callback: () => {
|
||||
ReglesOptionelles.set(options.settingConfirmer, false);
|
||||
options.onAction();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -132,21 +132,21 @@ export class RdDDice {
|
||||
}
|
||||
}
|
||||
|
||||
static async rollTotal(formula, options = { showDice: HIDE_DICE }) {
|
||||
return (await RdDDice.roll(formula, options)).total;
|
||||
}
|
||||
|
||||
static async roll(formula, options = { showDice: SHOW_DICE, rollMode: undefined }) {
|
||||
const roll = new Roll(RdDDice._formulaOrFake(formula, options));
|
||||
const roll = new Roll(formula);
|
||||
await roll.evaluate({ async: true });
|
||||
await this.showDiceSoNice(roll, options);
|
||||
if (options.showDice != HIDE_DICE) {
|
||||
await this.showDiceSoNice(roll, options.rollMode ?? game.settings.get("core", "rollMode"));
|
||||
}
|
||||
return roll;
|
||||
}
|
||||
|
||||
static async rollTotal(formula, options = { showDice: HIDE_DICE}) {
|
||||
const roll = await RdDDice.roll(formula, options);
|
||||
return roll.total;
|
||||
}
|
||||
|
||||
static async rollOneOf(array) {
|
||||
if (array == undefined || array.length == 0) {
|
||||
return undefined;
|
||||
}
|
||||
const roll = await RdDDice.rollTotal(`1d${array.length}`);
|
||||
return array[roll - 1];
|
||||
}
|
||||
@ -160,106 +160,27 @@ export class RdDDice {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async showDiceSoNice(roll, options) {
|
||||
if (options.showDice == HIDE_DICE || !game.modules.get("dice-so-nice")?.active || !game.dice3d) {
|
||||
return;
|
||||
}
|
||||
|
||||
let { whisper, blind } = RdDDice._getWhisperBlind(options);
|
||||
if (options.forceDiceResult?.total) {
|
||||
let terms = await RdDDice._getForcedTerms(options);
|
||||
if (terms) {
|
||||
await game.dice3d.show({ throws: [{ dice: terms }] })
|
||||
return;
|
||||
static async showDiceSoNice(roll, rollMode) {
|
||||
if (game.modules.get("dice-so-nice")?.active) {
|
||||
if (game.dice3d) {
|
||||
let whisper = null;
|
||||
let blind = false;
|
||||
rollMode = rollMode ?? game.settings.get("core", "rollMode");
|
||||
switch (rollMode) {
|
||||
case "blindroll": //GM only
|
||||
blind = true;
|
||||
case "gmroll": //GM + rolling player
|
||||
whisper = ChatUtility.getUsers(user => user.isGM);
|
||||
break;
|
||||
case "roll": //everybody
|
||||
whisper = ChatUtility.getUsers(user => user.active);
|
||||
break;
|
||||
case "selfroll":
|
||||
whisper = [game.user.id];
|
||||
break;
|
||||
}
|
||||
await game.dice3d.showForRoll(roll, game.user, true, whisper, blind);
|
||||
}
|
||||
}
|
||||
await game.dice3d.showForRoll(roll, game.user, true, whisper, blind);
|
||||
}
|
||||
|
||||
static _formulaOrFake(formula, options) {
|
||||
if (options?.forceDiceResult?.total) {
|
||||
options.forceDiceResult.formula = formula;
|
||||
return options.forceDiceResult.total.toString()
|
||||
}
|
||||
return formula;
|
||||
}
|
||||
|
||||
static async _getForcedTerms(options) {
|
||||
const total = options.forceDiceResult.total;
|
||||
switch (options.forceDiceResult.formula) {
|
||||
case '1d100':
|
||||
return terms1d100(total);
|
||||
case "2d10":
|
||||
return await terms2d10(total);
|
||||
}
|
||||
return undefined;
|
||||
|
||||
function terms1d100(total) {
|
||||
const unites = total % 10;
|
||||
const dizaines = Math.floor(total / 10);
|
||||
return [{
|
||||
resultLabel: dizaines * 10,
|
||||
d100Result: total,
|
||||
result: dizaines,
|
||||
type: "d100",
|
||||
vectors: [],
|
||||
options: {}
|
||||
},
|
||||
{
|
||||
resultLabel: unites,
|
||||
d100Result: total,
|
||||
result: unites,
|
||||
type: "d10",
|
||||
vectors: [],
|
||||
options: {}
|
||||
}];
|
||||
}
|
||||
|
||||
async function terms2d10(total) {
|
||||
if (total>20 || total<2) { return undefined }
|
||||
let first = await RdDDice.d10();
|
||||
let second = Math.min(total-first, 10);
|
||||
first = Math.max(first, total-second);
|
||||
return [{
|
||||
resultLabel:first,
|
||||
result: first,
|
||||
type: "d10",
|
||||
vectors: [],
|
||||
options: {}
|
||||
},
|
||||
{
|
||||
resultLabel: second,
|
||||
result: second,
|
||||
type: "d10",
|
||||
vectors: [],
|
||||
options: {}
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
static async d10() {
|
||||
let roll = new Roll('1d10');
|
||||
await roll.evaluate({ async: true });
|
||||
return roll.total;
|
||||
}
|
||||
|
||||
static _getWhisperBlind(options) {
|
||||
let whisper = undefined;
|
||||
let blind = false;
|
||||
let rollMode = options.rollMode ?? game.settings.get("core", "rollMode");
|
||||
switch (rollMode) {
|
||||
case "blindroll": //GM only
|
||||
blind = true;
|
||||
case "gmroll": //GM + rolling player
|
||||
whisper = ChatUtility.getUsers(user => user.isGM);
|
||||
break;
|
||||
case "roll": //everybody
|
||||
whisper = ChatUtility.getUsers(user => user.active);
|
||||
break;
|
||||
case "selfroll":
|
||||
whisper = [game.user.id];
|
||||
break;
|
||||
}
|
||||
return { whisper, blind };
|
||||
}
|
||||
}
|
@ -18,19 +18,18 @@ const tableGemmes = {
|
||||
export class RdDGemme extends Item {
|
||||
|
||||
static getGemmeTypeOptionList() {
|
||||
// TODO: look how to map object key-value pairs
|
||||
let options = ""
|
||||
for (let gemmeKey in tableGemmes) {
|
||||
options += `<option value="${gemmeKey}">${tableGemmes[gemmeKey].label}</option>`
|
||||
let gemmeData = tableGemmes[gemmeKey];
|
||||
options += `<option value="${gemmeKey}">${gemmeData.label}</option>`
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
|
||||
static calculDataDerivees(gemme) {
|
||||
gemme.system.cout = (gemme.system.taille * gemme.system.purete) + gemme.system.qualite;
|
||||
gemme.system.inertie = 7 - gemme.system.purete;
|
||||
gemme.system.enchantabilite = gemme.system.taille - gemme.system.inertie;
|
||||
static calculDataDerivees(data) {
|
||||
data.cout = (data.taille * data.purete) + data.qualite;
|
||||
data.inertie = 7 - data.purete;
|
||||
data.enchantabilite = data.taille - data.inertie;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,75 +1,76 @@
|
||||
/* -------------------------------------------- */
|
||||
import { RdDUtility } from "./rdd-utility.js";
|
||||
import { Misc } from "./misc.js";
|
||||
import { RdDCalendrier } from "./rdd-calendrier.js";
|
||||
import { Grammar } from "./grammar.js";
|
||||
import { SystemCompendiums } from "./settings/system-compendiums.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class RdDHerbes extends Item {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async initializeHerbes() {
|
||||
this.herbesSoins = await RdDHerbes.listCategorieHerbes('Soin');
|
||||
this.herbesRepos = await RdDHerbes.listCategorieHerbes('Repos');
|
||||
static isHerbeSoin( botaniqueItem ) {
|
||||
return Misc.templateData(botaniqueItem).categorie == 'Soin';
|
||||
}
|
||||
|
||||
static async listCategorieHerbes(categorie) {
|
||||
const herbes = await SystemCompendiums.getWorldOrCompendiumItems('herbe', 'faune-flore-mineraux');
|
||||
return herbes.filter(it => Grammar.equalsInsensitive(it.system.categorie, categorie));
|
||||
/* -------------------------------------------- */
|
||||
static isHerbeRepos( botaniqueItem ) {
|
||||
return Misc.templateData(botaniqueItem).categorie == 'Repos';
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static buildHerbesList(listeHerbes, max) {
|
||||
static async initializeHerbes( ) {
|
||||
this.herbesSoins = await RdDUtility.loadCompendium('foundryvtt-reve-de-dragon.botanique', item => this.isHerbeSoin(item));
|
||||
this.herbesRepos = await RdDUtility.loadCompendium('foundryvtt-reve-de-dragon.botanique', item => this.isHerbeRepos(item));
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static buildHerbesList(listHerbes, max) {
|
||||
let list = {}
|
||||
for (let herbe of listeHerbes) {
|
||||
let brins = max - herbe.system.niveau;
|
||||
list[herbe.name] = `${herbe.name} (Bonus: ${herbe.system.niveau}, Brins: ${brins})`;
|
||||
for ( let herbe of listHerbes) {
|
||||
let herbeData = Misc.templateData(herbe);
|
||||
let brins = max - herbeData.niveau;
|
||||
list[herbe.data.name] = `${herbe.data.name} (Bonus: ${herbeData.niveau}, Brins: ${brins})`;
|
||||
}
|
||||
list['Autre'] = 'Autre (Bonus: variable, Brins: variable)'
|
||||
return list;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async updatePotionData(formData) {
|
||||
formData.isSoins = formData.system.categorie.includes('Soin');
|
||||
formData.isRepos = formData.system.categorie.includes('Repos');
|
||||
if (formData.isSoins) {
|
||||
RdDHerbes.calculBonusHerbe(formData, this.herbesSoins, 12);
|
||||
}
|
||||
if (formData.isRepos) {
|
||||
RdDHerbes.calculBonusHerbe(formData, this.herbesRepos, 7);
|
||||
}
|
||||
formData.herbesSoins = RdDHerbes.buildHerbesList(this.herbesSoins, 12);
|
||||
formData.herbesRepos = RdDHerbes.buildHerbesList(this.herbesRepos, 7);
|
||||
static updatePotionData( formData ) {
|
||||
formData.herbesSoins = this.buildHerbesList(this.herbesSoins, 12);
|
||||
formData.herbesRepos = this.buildHerbesList(this.herbesRepos, 7);
|
||||
formData.jourMoisOptions = RdDCalendrier.buildJoursMois();
|
||||
formData.dateActuelle = game.system.rdd.calendrier.getDateFromIndex();
|
||||
formData.splitDate = game.system.rdd.calendrier.getDayMonthFromIndex(formData.system.prdate);
|
||||
}
|
||||
formData.splitDate = game.system.rdd.calendrier.getNumericDateFromIndex(formData.data.prdate);
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static calculPuissancePotion(potion) {
|
||||
return potion.system.herbebonus * potion.system.pr;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static calculPointsRepos(potion) {
|
||||
return potion.system.herbebonus * potion.system.pr;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static calculPointsGuerison(potion) {
|
||||
return potion.system.herbebonus * potion.system.pr;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static calculBonusHerbe(formData, herbesList, max) {
|
||||
if (Number(formData.system.herbebrins)) {
|
||||
let herbe = herbesList.find(item => item.name.toLowerCase() == formData.system.herbe.toLowerCase());
|
||||
if (herbe) {
|
||||
const brinsRequis = max - herbe.system.niveau;
|
||||
const brinsManquants = Math.max(brinsRequis - formData.system.herbebrins, 0);
|
||||
formData.system.herbebonus = Math.max(herbe.system.niveau - brinsManquants, 0);
|
||||
}
|
||||
if (formData.data.categorie.includes('Soin') ) {
|
||||
formData.isHerbe = true;
|
||||
this.computeHerbeBonus(formData, this.herbesSoins, 12);
|
||||
} else if (formData.data.categorie.includes('Repos')) {
|
||||
formData.isRepos = true;
|
||||
this.computeHerbeBonus(formData, this.herbesRepos, 7);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static calculePointsRepos( data ) {
|
||||
return data.herbebonus * data.pr;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static calculePointsGuerison( data ){
|
||||
return data.herbebonus * data.pr;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static computeHerbeBonus( formData, herbesList, max) {
|
||||
if ( Number(formData.data.herbebrins) ) {
|
||||
let herbe = herbesList.find(item => item.name.toLowerCase() == formData.data.herbe.toLowerCase() );
|
||||
if( herbe ) {
|
||||
let herbeData = Misc.templateData(herbe);
|
||||
let brinsBase = max - herbeData.niveau;
|
||||
//console.log(herbeData, brinsBase, formData.data.herbebrins);
|
||||
formData.data.herbebonus = Math.max(herbeData.niveau - Math.max(brinsBase - formData.data.herbebrins, 0), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,46 +1,65 @@
|
||||
import { Misc } from "./misc.js";
|
||||
|
||||
export class RdDHotbar {
|
||||
|
||||
static async addToHotbar(item, slot) {
|
||||
let command = `game.system.rdd.RdDHotbar.rollMacro("${item.name}", "${item.type}");`;
|
||||
let macro = game.macros.contents.find(m => (m.name === item.name) && (m.command === command));
|
||||
if (!macro) {
|
||||
macro = await Macro.create({
|
||||
name: item.name,
|
||||
type: "script",
|
||||
img: item.img,
|
||||
command: command
|
||||
}, { displaySheet: false })
|
||||
}
|
||||
await game.user.assignHotbarMacro(macro, slot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a macro when dropping an entity on the hotbar
|
||||
* Item - open roll dialog for item
|
||||
* Actor - open actor sheet
|
||||
* Journal - open journal sheet
|
||||
*/
|
||||
static initDropbar() {
|
||||
static initDropbar( ) {
|
||||
|
||||
Hooks.on("hotbarDrop", (bar, documentData, slot) => {
|
||||
|
||||
// Create item macro if rollable item - weapon, spell, prayer, trait, or skill
|
||||
if (documentData.type == "Item") {
|
||||
let item = fromUuidSync(documentData.uuid)
|
||||
if (item == undefined) {
|
||||
item = this.actor.items.get(documentData.uuid)
|
||||
}
|
||||
console.log("DROP", documentData, item)
|
||||
if (!item || (item.type != "arme" && item.type != "competence")) {
|
||||
return true
|
||||
}
|
||||
this.addToHotbar(item, slot)
|
||||
return false
|
||||
Hooks.on("hotbarDrop", async (bar, documentData, slot) => {
|
||||
// Create item macro if rollable item - weapon, spell, prayer, trait, or skill
|
||||
if (documentData.type == "Item") {
|
||||
if (documentData.data.type != "arme" && documentData.data.type != "competence" )
|
||||
return
|
||||
let item = documentData.data
|
||||
let command = `game.system.rdd.RdDHotbar.rollMacro("${item.name}", "${item.type}");`;
|
||||
let macro = game.macros.contents.find(m => (m.name === item.name) && (m.command === command));
|
||||
if (!macro) {
|
||||
macro = await Macro.create({
|
||||
name: item.name,
|
||||
type: "script",
|
||||
img: item.img,
|
||||
command: command
|
||||
}, { displaySheet: false })
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
game.user.assignHotbarMacro(macro, slot);
|
||||
}
|
||||
// Create a macro to open the actor sheet of the actor dropped on the hotbar
|
||||
else if (documentData.type == "Actor") {
|
||||
let actor = game.actors.get(documentData.id);
|
||||
let command = `game.actors.get("${documentData.id}").sheet.render(true)`
|
||||
let macro = game.macros.contents.find(m => (m.name === actor.name) && (m.command === command));
|
||||
if (!macro) {
|
||||
macro = await Macro.create({
|
||||
name: actor.data.name,
|
||||
type: "script",
|
||||
img: actor.data.img,
|
||||
command: command
|
||||
}, { displaySheet: false })
|
||||
game.user.assignHotbarMacro(macro, slot);
|
||||
}
|
||||
}
|
||||
// Create a macro to open the journal sheet of the journal dropped on the hotbar
|
||||
else if (documentData.type == "JournalEntry") {
|
||||
let journal = game.journal.get(documentData.id);
|
||||
let command = `game.journal.get("${documentData.id}").sheet.render(true)`
|
||||
let macro = game.macros.contents.find(m => (m.name === journal.name) && (m.command === command));
|
||||
if (!macro) {
|
||||
macro = await Macro.create({
|
||||
name: journal.data.name,
|
||||
type: "script",
|
||||
img: "systems/foundryvtt-reve-de-dragon/icons/templates/icone_parchement_vierge.webp",
|
||||
command: command
|
||||
}, { displaySheet: false })
|
||||
game.user.assignHotbarMacro(macro, slot);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
/** Roll macro */
|
||||
@ -50,17 +69,15 @@ export class RdDHotbar {
|
||||
if (speaker.token) actor = game.actors.tokens[speaker.token];
|
||||
if (!actor) actor = game.actors.get(speaker.actor);
|
||||
|
||||
let item = actor?.items.find(it => it.name === itemName && it.type == itemType) ?? undefined;
|
||||
if (!item) {
|
||||
return ui.notifications.warn(`Impossible de trouver l'objet de cette macro`);
|
||||
}
|
||||
let item = Misc.data(actor?.items.find(it => it.name === itemName && it.type == itemType));
|
||||
if (!item) return ui.notifications.warn(`Impossible de trouver l'objet de cette macro`);
|
||||
|
||||
// Trigger the item roll
|
||||
switch (item.type) {
|
||||
case "arme":
|
||||
return actor.rollArme(item);
|
||||
case "competence":
|
||||
return actor.rollCompetence(itemName);
|
||||
return actor.rollCompetence( itemName );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,13 @@
|
||||
/**
|
||||
* RdD system
|
||||
* Author: LeRatierBretonnien
|
||||
* Software License: GNU GPLv3
|
||||
*/
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/* -------------------------------------------- */
|
||||
// Import Modules
|
||||
import { SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
|
||||
import { RdDActor } from "./actor.js";
|
||||
import { RdDItemSheet } from "./item-sheet.js";
|
||||
@ -13,9 +23,10 @@ import { RdDTokenHud } from "./rdd-token-hud.js";
|
||||
import { RdDCommands } from "./rdd-commands.js";
|
||||
import { RdDCombatManager, RdDCombat } from "./rdd-combat.js";
|
||||
import { ChatUtility } from "./chat-utility.js";
|
||||
import { StatusEffects } from "./settings/status-effects.js";
|
||||
import { StatusEffects } from "./status-effects.js";
|
||||
import { RddCompendiumOrganiser } from "./rdd-compendium-organiser.js";
|
||||
import { ReglesOptionelles } from "./settings/regles-optionelles.js";
|
||||
import { ReglesOptionelles } from "./regles-optionelles.js";
|
||||
import { TMRRencontres } from "./tmr-rencontres.js";
|
||||
import { RdDHotbar } from "./rdd-hotbar-drop.js"
|
||||
import { EffetsDraconiques } from "./tmr/effets-draconiques.js";
|
||||
import { RdDHerbes } from "./rdd-herbes.js";
|
||||
@ -24,291 +35,295 @@ import { RdDDice } from "./rdd-dice.js";
|
||||
import { RdDPossession } from "./rdd-possession.js";
|
||||
import { RdDSigneDraconiqueItemSheet } from "./item-signedraconique-sheet.js";
|
||||
import { Misc } from "./misc.js";
|
||||
import { Migrations } from './migrations.js';
|
||||
import { DialogChronologie } from "./dialog-chronologie.js";
|
||||
import { SystemCompendiums } from "./settings/system-compendiums.js";
|
||||
import { RdDRencontreItemSheet } from "./item-rencontre-sheet.js";
|
||||
import { TMRRencontres } from "./tmr-rencontres.js";
|
||||
import { RdDHerbeItemSheet } from "./item-herbe-sheet.js";
|
||||
import { Environnement } from "./environnement.js";
|
||||
import { RdDIngredientItemSheet } from "./item-ingredient-sheet.js";
|
||||
import { RdDFauneItemSheet } from "./item-faune-sheet.js";
|
||||
import { RdDConteneurItemSheet } from "./item-conteneur-sheet.js";
|
||||
import { RdDServiceItemSheet } from "./item-service-sheet.js";
|
||||
import { RdDItemService } from "./item-service.js";
|
||||
|
||||
/**
|
||||
* RdD system
|
||||
* Author: LeRatierBretonnien
|
||||
* Software License: GNU GPLv3
|
||||
*/
|
||||
export class SystemReveDeDragon {
|
||||
/* -------------------------------------------- */
|
||||
/* Foundry VTT Initialization */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
static start() {
|
||||
const system = new SystemReveDeDragon();
|
||||
Hooks.once('init', async () => await system.onInit());
|
||||
Hooks.once('diceSoNiceReady', (dice3d) => RdDDice.diceSoNiceReady(dice3d));
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.RdDUtility = RdDUtility;
|
||||
this.RdDHotbar = RdDHotbar;
|
||||
this.itemClasses = {
|
||||
service: RdDItemService
|
||||
}
|
||||
this.actorClasses = {
|
||||
}
|
||||
|
||||
/************************************************************************************/
|
||||
Hooks.once("init", async function () {
|
||||
console.log(`Initializing Reve de Dragon System`);
|
||||
|
||||
// preload handlebars templates
|
||||
RdDUtility.preloadHandlebarsTemplates();
|
||||
// Create useful storage space
|
||||
game.system.rdd = {
|
||||
TMRUtility,
|
||||
RdDUtility,
|
||||
RdDHotbar,
|
||||
RdDPossession,
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Foundry VTT Initialization */
|
||||
game.settings.register(SYSTEM_RDD, "accorder-entite-cauchemar", {
|
||||
name: "Accorder le rêve aux entités",
|
||||
hint: "A quel moment les personnages doivent accorder leur rêve aux entités de cauchemar",
|
||||
scope: "world",
|
||||
config: true,
|
||||
type: String,
|
||||
choices: { // If choices are defined, the resulting setting will be a select menu
|
||||
"avant-attaque": "Avant l'attaque",
|
||||
"avant-defense": "Avant la défense",
|
||||
"avant-encaissement": "Avant l'encaissement",
|
||||
},
|
||||
default: "avant-encaissement"
|
||||
});
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async onInit() {
|
||||
game.system.rdd = this;
|
||||
game.settings.register(SYSTEM_RDD, "calendrier", {
|
||||
name: "calendrier",
|
||||
scope: "world",
|
||||
config: false,
|
||||
default: RdDCalendrier.getCalendrier(0),
|
||||
type: Object
|
||||
});
|
||||
|
||||
console.log(`Initializing Reve de Dragon System`);
|
||||
/* -------------------------------------------- */
|
||||
game.settings.register(SYSTEM_RDD, "migration-png-webp-1.5.34", {
|
||||
name: "calendrier",
|
||||
scope: "world",
|
||||
config: false,
|
||||
default: false,
|
||||
type: Boolean
|
||||
});
|
||||
|
||||
// preload handlebars templates
|
||||
RdDUtility.preloadHandlebarsTemplates();
|
||||
/* -------------------------------------------- */
|
||||
game.settings.register(SYSTEM_RDD, "liste-nombre-astral", {
|
||||
name: "liste-nombre-astral",
|
||||
scope: "world",
|
||||
config: false,
|
||||
default: [],
|
||||
type: Object
|
||||
});
|
||||
|
||||
/* -------------------------------------------- */
|
||||
game.settings.register(SYSTEM_RDD, "accorder-entite-cauchemar", {
|
||||
name: "Accorder le rêve aux entités",
|
||||
hint: "A quel moment les personnages doivent accorder leur rêve aux entités de cauchemar",
|
||||
scope: "world",
|
||||
config: true,
|
||||
type: String,
|
||||
choices: { // If choices are defined, the resulting setting will be a select menu
|
||||
"avant-attaque": "Avant l'attaque",
|
||||
"avant-defense": "Avant la défense",
|
||||
"avant-encaissement": "Avant l'encaissement",
|
||||
},
|
||||
default: "avant-encaissement"
|
||||
});
|
||||
/* -------------------------------------------- */
|
||||
game.settings.register(SYSTEM_RDD, "calendrier-pos", {
|
||||
name: "calendrierPos",
|
||||
scope: "client",
|
||||
config: false,
|
||||
default: RdDCalendrier.createCalendrierPos(),
|
||||
type: Object
|
||||
});
|
||||
/* -------------------------------------------- */
|
||||
game.settings.register(SYSTEM_RDD, "supprimer-dialogues-combat-chat", {
|
||||
name: "Supprimer les dialogues de combat",
|
||||
hint: "Si désactivée, tous les dialogues de combat sont conservés dans la conversation",
|
||||
scope: "world",
|
||||
config: true,
|
||||
default: true,
|
||||
type: Boolean
|
||||
});
|
||||
/* -------------------------------------------- */
|
||||
game.settings.register(SYSTEM_RDD, "activer-sons-audio", {
|
||||
name: "Activer les bruitages intégrés",
|
||||
hint: "Si activé, certaines actions en jeu déclenchent un son d'ambiance",
|
||||
scope: "world",
|
||||
config: true,
|
||||
default: true,
|
||||
type: Boolean
|
||||
});
|
||||
/* -------------------------------------------- */
|
||||
game.settings.register(SYSTEM_RDD, "appliquer-famine-soif", {
|
||||
name: "Notifier de la famine et la soif pour",
|
||||
hint: "Indique si les cas de famine et de soif seront indiqués durant Château Dormant",
|
||||
scope: "world",
|
||||
config: true,
|
||||
type: String,
|
||||
choices: {
|
||||
"aucun": "ni la famine, ni la soif",
|
||||
"famine": "seulement la famine",
|
||||
"famine-soif": "la famine et la soif",
|
||||
},
|
||||
default: "aucun"
|
||||
});
|
||||
|
||||
/* -------------------------------------------- */
|
||||
game.settings.register(SYSTEM_RDD, "calendrier", {
|
||||
name: "calendrier",
|
||||
scope: "world",
|
||||
config: false,
|
||||
default: RdDCalendrier.createCalendrierInitial(),
|
||||
type: Object
|
||||
});
|
||||
/* -------------------------------------------- */
|
||||
// Set an initiative formula for the system
|
||||
CONFIG.Combat.initiative = {
|
||||
formula: "1+(1d6/10)",
|
||||
decimals: 2
|
||||
};
|
||||
|
||||
/* -------------------------------------------- */
|
||||
game.settings.register(SYSTEM_RDD, "liste-nombre-astral", {
|
||||
name: "liste-nombre-astral",
|
||||
scope: "world",
|
||||
config: false,
|
||||
default: [],
|
||||
type: Object
|
||||
});
|
||||
/* -------------------------------------------- */
|
||||
game.socket.on(SYSTEM_SOCKET_ID, sockmsg => {
|
||||
console.log(">>>>> MSG RECV", sockmsg);
|
||||
|
||||
/* -------------------------------------------- */
|
||||
game.settings.register(SYSTEM_RDD, "calendrier-pos", {
|
||||
name: "calendrierPos",
|
||||
scope: "client",
|
||||
config: false,
|
||||
default: RdDCalendrier.createCalendrierPos(),
|
||||
type: Object
|
||||
});
|
||||
RdDUtility.onSocketMessage(sockmsg);
|
||||
RdDCombat.onSocketMessage(sockmsg);
|
||||
ChatUtility.onSocketMessage(sockmsg);
|
||||
RdDActor.onSocketMessage(sockmsg);
|
||||
});
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
game.settings.register(SYSTEM_RDD, "supprimer-dialogues-combat-chat", {
|
||||
name: "Supprimer les dialogues de combat",
|
||||
hint: "Si désactivée, tous les dialogues de combat sont conservés dans la conversation",
|
||||
scope: "world",
|
||||
config: true,
|
||||
default: true,
|
||||
type: Boolean
|
||||
});
|
||||
/* -------------------------------------------- */
|
||||
game.settings.register(SYSTEM_RDD, "activer-sons-audio", {
|
||||
name: "Activer les bruitages intégrés",
|
||||
hint: "Si activé, certaines actions en jeu déclenchent un son d'ambiance",
|
||||
scope: "world",
|
||||
config: true,
|
||||
default: true,
|
||||
type: Boolean
|
||||
});
|
||||
/* -------------------------------------------- */
|
||||
game.settings.register(SYSTEM_RDD, "appliquer-famine-soif", {
|
||||
name: "Notifier de la famine et la soif pour",
|
||||
hint: "Indique si les cas de famine et de soif seront indiqués durant Château Dormant",
|
||||
scope: "world",
|
||||
config: true,
|
||||
type: String,
|
||||
choices: {
|
||||
"aucun": "ni la famine, ni la soif",
|
||||
"famine": "seulement la famine",
|
||||
"famine-soif": "la famine et la soif",
|
||||
},
|
||||
default: "aucun"
|
||||
});
|
||||
|
||||
/* -------------------------------------------- */
|
||||
// Set an initiative formula for the system
|
||||
CONFIG.Combat.initiative = {
|
||||
formula: "1+(1d6/10)",
|
||||
decimals: 2
|
||||
};
|
||||
|
||||
/* -------------------------------------------- */
|
||||
game.socket.on(SYSTEM_SOCKET_ID, async (sockmsg) => {
|
||||
console.log(">>>>> MSG RECV", sockmsg);
|
||||
try {
|
||||
RdDUtility.onSocketMessage(sockmsg);
|
||||
RdDCombat.onSocketMessage(sockmsg);
|
||||
ChatUtility.onSocketMessage(sockmsg);
|
||||
RdDActor.onSocketMessage(sockmsg);
|
||||
} catch (e) {
|
||||
console.error('game.socket.on(SYSTEM_SOCKET_ID) Exception: ', sockmsg, ' => ', e)
|
||||
}
|
||||
});
|
||||
|
||||
/* -------------------------------------------- */
|
||||
// Define custom Entity classes
|
||||
CONFIG.Actor.documentClass = RdDActor;
|
||||
CONFIG.Item.documentClass = RdDItem;
|
||||
CONFIG.RDD = {
|
||||
resolutionTable: RdDResolutionTable.resolutionTable,
|
||||
carac_array: RdDUtility.getCaracArray(),
|
||||
ajustementsConditions: RdDUtility.getAjustementsConditions(),
|
||||
difficultesLibres: RdDUtility.getDifficultesLibres()
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
// Register sheet application classes
|
||||
Actors.unregisterSheet("core", ActorSheet);
|
||||
Actors.registerSheet(SYSTEM_RDD, RdDActorSheet, { types: ["personnage"], makeDefault: true });
|
||||
Actors.registerSheet(SYSTEM_RDD, RdDActorCreatureSheet, { types: ["creature"], makeDefault: true });
|
||||
Actors.registerSheet(SYSTEM_RDD, RdDActorVehiculeSheet, { types: ["vehicule"], makeDefault: true });
|
||||
Actors.registerSheet(SYSTEM_RDD, RdDActorEntiteSheet, { types: ["entite"], makeDefault: true });
|
||||
Items.unregisterSheet("core", ItemSheet);
|
||||
|
||||
RdDItemSheet.register(RdDSigneDraconiqueItemSheet);
|
||||
RdDItemSheet.register(RdDRencontreItemSheet);
|
||||
RdDItemSheet.register(RdDConteneurItemSheet);
|
||||
RdDItemSheet.register(RdDHerbeItemSheet);
|
||||
RdDItemSheet.register(RdDFauneItemSheet);
|
||||
RdDItemSheet.register(RdDIngredientItemSheet);
|
||||
RdDItemSheet.register(RdDServiceItemSheet);
|
||||
|
||||
Items.registerSheet(SYSTEM_RDD, RdDItemSheet, {
|
||||
types: [
|
||||
"competence", "competencecreature",
|
||||
"recettealchimique", "musique", "chant", "danse", "jeu", "recettecuisine", "oeuvre",
|
||||
"objet", "arme", "armure", "livre", "potion", "munition",
|
||||
"monnaie", "nourritureboisson", "gemme",
|
||||
"meditation", "queue", "ombre", "souffle", "tete", "casetmr", "sort", "sortreserve",
|
||||
"nombreastral", "tache", "maladie", "poison", "possession",
|
||||
"tarot", "extraitpoetique"
|
||||
], makeDefault: true
|
||||
});
|
||||
CONFIG.Combat.documentClass = RdDCombatManager;
|
||||
|
||||
// préparation des différents modules
|
||||
SystemCompendiums.init();
|
||||
DialogChronologie.init();
|
||||
ReglesOptionelles.init();
|
||||
RdDUtility.init();
|
||||
RdDDice.init();
|
||||
RdDCommands.init();
|
||||
RdDCombat.init();
|
||||
RdDCombatManager.init();
|
||||
RdDTokenHud.init();
|
||||
RdDActor.init();
|
||||
RddCompendiumOrganiser.init();
|
||||
EffetsDraconiques.init()
|
||||
TMRUtility.init();
|
||||
RdDHotbar.initDropbar();
|
||||
RdDPossession.init();
|
||||
TMRRencontres.init();
|
||||
Environnement.init();
|
||||
|
||||
Hooks.once('ready', () => this.onReady());
|
||||
/* -------------------------------------------- */
|
||||
// Define custom Entity classes
|
||||
CONFIG.Actor.documentClass = RdDActor;
|
||||
CONFIG.Item.documentClass = RdDItem;
|
||||
CONFIG.RDD = {
|
||||
resolutionTable: RdDResolutionTable.resolutionTable,
|
||||
carac_array: RdDUtility.getCaracArray(),
|
||||
ajustementsConditions: RdDUtility.getAjustementsConditions(),
|
||||
difficultesLibres: RdDUtility.getDifficultesLibres()
|
||||
}
|
||||
|
||||
async onReady() {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Foundry VTT Initialization */
|
||||
/* -------------------------------------------- */
|
||||
// CSS patch for v9
|
||||
if (game.version) {
|
||||
let sidebar = document.getElementById("sidebar");
|
||||
sidebar.style.width = "min-content";
|
||||
}
|
||||
|
||||
if (Misc.isUniqueConnectedGM()) {
|
||||
new Migrations().migrate();
|
||||
}
|
||||
|
||||
StatusEffects.onReady();
|
||||
RdDHerbes.initializeHerbes();
|
||||
RdDDice.onReady();
|
||||
/* -------------------------------------------- */
|
||||
/* Affiche/Init le calendrier */
|
||||
let calendrier = new RdDCalendrier();
|
||||
let templatePath = "systems/foundryvtt-reve-de-dragon/templates/calendar-template.html";
|
||||
let templateData = {};
|
||||
renderTemplate(templatePath, templateData).then(html => {
|
||||
calendrier.render(true);
|
||||
});
|
||||
game.system.rdd.calendrier = calendrier; // Reference;
|
||||
|
||||
// Avertissement si joueur sans personnage
|
||||
if (!game.user.isGM && game.user.character == undefined) {
|
||||
ui.notifications.info("Attention ! Vous n'êtes connecté à aucun personnage !");
|
||||
ChatMessage.create({
|
||||
content: "<b>ATTENTION</b> Le joueur " + game.user.name + " n'est connecté à aucun personnage !",
|
||||
user: game.user.id
|
||||
});
|
||||
}
|
||||
if (Misc.isUniqueConnectedGM()) {
|
||||
this.messageDeBienvenue();
|
||||
this.registerUsageCount(SYSTEM_RDD);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
messageDeBienvenue() {
|
||||
if (game.user.isGM) {
|
||||
ChatUtility.removeChatMessageContaining('<div id="message-bienvenue-rdd">');
|
||||
ChatMessage.create({
|
||||
user: game.user.id,
|
||||
content: `<div id="message-bienvenue-rdd"><span class="rdd-roll-part">Bienvenue dans le Rêve des Dragons !</span>
|
||||
// Register sheet application classes
|
||||
Actors.unregisterSheet("core", ActorSheet);
|
||||
Actors.registerSheet(SYSTEM_RDD, RdDActorSheet, { types: ["personnage"], makeDefault: true });
|
||||
Actors.registerSheet(SYSTEM_RDD, RdDActorCreatureSheet, { types: ["creature"], makeDefault: true });
|
||||
Actors.registerSheet(SYSTEM_RDD, RdDActorVehiculeSheet, { types: ["vehicule"], makeDefault: true });
|
||||
Actors.registerSheet(SYSTEM_RDD, RdDActorEntiteSheet, { types: ["entite"], makeDefault: true });
|
||||
Items.unregisterSheet("core", ItemSheet);
|
||||
Items.registerSheet(SYSTEM_RDD, RdDSigneDraconiqueItemSheet, {
|
||||
label: "Signe draconique",
|
||||
types: ["signedraconique"],
|
||||
makeDefault: true
|
||||
});
|
||||
Items.registerSheet(SYSTEM_RDD, RdDItemSheet, {
|
||||
types: ["arme", "armure", "objet", "arme", "armure", "conteneur", "competence", "sort", "herbe", "ingredient", "livre", "potion", "munition", "rencontresTMR", "queue", "ombre", "souffle",
|
||||
"tete", "competencecreature", "tarot", "monnaie", "nombreastral", "tache", "meditation", "casetmr", "recettealchimique", "gemme",
|
||||
"musique", "chant", "danse", "jeu", "recettecuisine", "maladie", "poison", "oeuvre", "nourritureboisson", "possession"], makeDefault: true
|
||||
});
|
||||
CONFIG.Combat.documentClass = RdDCombatManager;
|
||||
|
||||
// préparation des différents modules
|
||||
ReglesOptionelles.init();
|
||||
RdDUtility.init();
|
||||
RdDDice.init();
|
||||
RdDCommands.init();
|
||||
RdDCombat.init();
|
||||
RdDCombatManager.init();
|
||||
RdDTokenHud.init();
|
||||
RdDActor.init();
|
||||
RddCompendiumOrganiser.init();
|
||||
EffetsDraconiques.init()
|
||||
TMRUtility.init();
|
||||
TMRRencontres.init();
|
||||
RdDHotbar.initDropbar();
|
||||
RdDPossession.init();
|
||||
});
|
||||
|
||||
/* -------------------------------------------- */
|
||||
function messageDeBienvenue() {
|
||||
if (game.user.isGM) {
|
||||
ChatUtility.removeChatMessageContaining('<div id="message-bienvenue-rdd">');
|
||||
ChatMessage.create({
|
||||
user: game.user.id,
|
||||
content: `<div id="message-bienvenue-rdd"><span class="rdd-roll-part">Bienvenue dans le Rêve des Dragons !</span>
|
||||
<br>Vous trouverez quelques informations pour démarrer dans ce document : @Compendium[foundryvtt-reve-de-dragon.rappel-des-regles.7uGrUHGdPu0EmIu2]{Documentation MJ/Joueurs}
|
||||
<br>La commande <code>/aide</code> dans le chat permet de voir les commandes spécifiques à Rêve de Dragon.</div>
|
||||
` });
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
// Register world usage statistics
|
||||
function registerUsageCount( registerKey ) {
|
||||
if ( game.user.isGM ) {
|
||||
game.settings.register(registerKey, "world-key", {
|
||||
name: "Unique world key",
|
||||
scope: "world",
|
||||
config: false,
|
||||
type: String
|
||||
});
|
||||
|
||||
let worldKey = game.settings.get(registerKey, "world-key")
|
||||
if ( worldKey == undefined || worldKey == "" ) {
|
||||
worldKey = randomID(32)
|
||||
game.settings.set(registerKey, "world-key", worldKey )
|
||||
}
|
||||
let regURL = `https://www.uberwald.me/fvtt_appcount/count.php?name="${registerKey}"&worldKey="${worldKey}"&version="${game.release.generation}.${game.release.build}"&system="${game.system.id}"&systemversion="${game.system.data.version}"`
|
||||
$.ajax(regURL)
|
||||
/* -------------------------------------------- */
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Foundry VTT Initialization */
|
||||
/* -------------------------------------------- */
|
||||
Hooks.once("ready", async function () {
|
||||
await migrationPngWebp_1_5_34()
|
||||
|
||||
StatusEffects.onReady();
|
||||
RdDHerbes.initializeHerbes();
|
||||
RdDDice.onReady();
|
||||
/* -------------------------------------------- */
|
||||
/* Affiche/Init le calendrier */
|
||||
let calendrier = new RdDCalendrier();
|
||||
let templatePath = "systems/foundryvtt-reve-de-dragon/templates/calendar-template.html";
|
||||
let templateData = {};
|
||||
renderTemplate(templatePath, templateData).then(html => {
|
||||
calendrier.render(true);
|
||||
});
|
||||
game.system.rdd.calendrier = calendrier; // Reference;
|
||||
|
||||
// Avertissement si joueur sans personnage
|
||||
if (!game.user.isGM && game.user.character == undefined) {
|
||||
ui.notifications.info("Attention ! Vous n'êtes connecté à aucun personnage !");
|
||||
ChatMessage.create({
|
||||
content: "<b>ATTENTION</b> Le joueur " + game.user.name + " n'est connecté à aucun personnage !",
|
||||
user: game.user.id
|
||||
});
|
||||
}
|
||||
if (Misc.isUniqueConnectedGM()) {
|
||||
messageDeBienvenue();
|
||||
registerUsageCount( SYSTEM_RDD );
|
||||
}
|
||||
});
|
||||
|
||||
async function migrationPngWebp_1_5_34() {
|
||||
if (!game.settings.get(SYSTEM_RDD, "migration-png-webp-1.5.34")) {
|
||||
const regexOldPngJpg = /(systems\/foundryvtt-reve-de-dragon\/icons\/.*)\.(png|jpg)/;
|
||||
const replaceWithWebp = '$1.webp';
|
||||
function convertImgToWebp(img) {
|
||||
return img.replace(regexOldPngJpg, replaceWithWebp);
|
||||
}
|
||||
function prepareDocumentsImgUpdate(documents) {
|
||||
return documents.filter(it => it.img && it.img.match(regexOldPngJpg))
|
||||
.map(it => {
|
||||
return { _id: it.id, img: convertImgToWebp(it.img) }
|
||||
});
|
||||
}
|
||||
const itemsUpdates = prepareDocumentsImgUpdate(game.items);
|
||||
const actorsUpdates = prepareDocumentsImgUpdate(game.actors);
|
||||
//Migrate system png to webp
|
||||
await Item.updateDocuments(itemsUpdates);
|
||||
await Actor.updateDocuments(actorsUpdates);
|
||||
game.actors.forEach(actor => {
|
||||
if (actor.data.token?.img && actor.data.token.img.match(regexOldPngJpg)) {
|
||||
actor.update({ "token.img": convertImgToWebp(actor.data.token.img) });
|
||||
}
|
||||
const actorItemsToUpdate = prepareDocumentsImgUpdate(actor.items);
|
||||
actor.updateEmbeddedDocuments('Item', actorItemsToUpdate);
|
||||
});
|
||||
game.settings.set(SYSTEM_RDD, "migration-png-webp-1.5.34", true)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
// Register world usage statistics
|
||||
async registerUsageCount(registerKey) {
|
||||
if (game.user.isGM) {
|
||||
game.settings.register("world", "world-key", {
|
||||
name: "Unique world key",
|
||||
scope: "world",
|
||||
config: false,
|
||||
default: "NONE",
|
||||
type: String
|
||||
});
|
||||
|
||||
let worldKey = game.settings.get("world", "world-key")
|
||||
if (worldKey == undefined || worldKey == "") {
|
||||
worldKey = randomID(32)
|
||||
game.settings.set("world", "world-key", worldKey)
|
||||
}
|
||||
let regURL = `https://www.uberwald.me/fvtt_appcount/count.php?name="${registerKey}"&worldKey="${worldKey}"&version="${game.release.generation}.${game.release.build}"&system="${game.system.id}"&systemversion="${game.system.version}"`
|
||||
$.ajax(regURL)
|
||||
/* -------------------------------------------- */
|
||||
}
|
||||
// CSS patch for v9
|
||||
if (game.version) {
|
||||
let sidebar = document.getElementById("sidebar");
|
||||
sidebar.style.width = "min-content";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SystemReveDeDragon.start();
|
||||
/* -------------------------------------------- */
|
||||
/* Dice-so-nice ready */
|
||||
/* -------------------------------------------- */
|
||||
Hooks.once('diceSoNiceReady', (dice3d) => RdDDice.diceSoNiceReady(dice3d));
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Foundry VTT chat message */
|
||||
/* -------------------------------------------- */
|
||||
Hooks.on("chatMessage", (html, content, msg) => {
|
||||
if (content[0] == '/') {
|
||||
let regExp = /(\S+)/g;
|
||||
let commands = content.match(regExp);
|
||||
if (game.system.rdd.commands.processChatCommand(commands, content, msg)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
|
@ -3,7 +3,6 @@ import { RdDCombat } from "./rdd-combat.js";
|
||||
import { RdDResolutionTable } from "./rdd-resolution-table.js";
|
||||
import { RdDRoll } from "./rdd-roll.js";
|
||||
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
|
||||
import { Targets } from "./targets.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* On part du principe qu'une entité démarre tjs
|
||||
@ -20,155 +19,23 @@ export class RdDPossession {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static searchPossessionFromEntite(attacker, defender) {
|
||||
let poss = attacker.items.find(poss => poss.type == 'possession' && poss.system.possedeid == defender.id);
|
||||
let poss = attacker.data.items.find(poss => poss.type == 'possession' && poss.data.data.possedeid == defender.data._id);
|
||||
if (!poss) {
|
||||
poss = defender.items.find(poss => poss.type == 'possession' && poss.system.possedeid == defender.id);
|
||||
poss = defender.data.items.find(poss => poss.type == 'possession' && poss.data.data.possedeid == defender.data._id);
|
||||
}
|
||||
return poss && duplicate(poss) || undefined;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async onAttaquePossession(target, attacker, competence, suitePossession = undefined) {
|
||||
const defender = target.actor;
|
||||
const fromEntite = RdDPossession.searchPossessionFromEntite(attacker, defender);
|
||||
const isNouvelle = !suitePossession && ! fromEntite;
|
||||
const possession = (suitePossession ?? fromEntite ?? (await RdDPossession.createPossession(attacker, defender)));
|
||||
|
||||
RdDPossession.$updateEtatPossession(possession)
|
||||
|
||||
let rollData = {
|
||||
mode: "possession",
|
||||
isECNIDefender: false,
|
||||
competence: competence,
|
||||
possession: possession,
|
||||
attacker: attacker,
|
||||
defender: defender,
|
||||
targetToken: Targets.extractTokenData(target)
|
||||
};
|
||||
if (attacker.isCreatureEntite()) {
|
||||
RdDItemCompetenceCreature.setRollDataCreature(rollData)
|
||||
}
|
||||
|
||||
await RdDPossession.$rollAttaquePossession(attacker, rollData, isNouvelle);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async onConjurerPossession(attacker, competence, possession) {
|
||||
possession = duplicate(possession);
|
||||
RdDPossession.$updateEtatPossession(possession)
|
||||
let rollData = {
|
||||
mode: "possession",
|
||||
isECNIDefender: true,
|
||||
competence: competence,
|
||||
possession: possession,
|
||||
attacker: attacker,
|
||||
defender: game.actors.get(possession.system.possesseurid)
|
||||
};
|
||||
await RdDPossession.$rollAttaquePossession(attacker, rollData);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async onDefensePossession(attackerId, defenderId, possessionId) {
|
||||
let attacker = game.actors.get(attackerId)
|
||||
let possession = attacker?.getPossession(possessionId)
|
||||
defenderId = defenderId ?? possession?.system.possesseurid ?? undefined
|
||||
let defender = game.actors.get(defenderId)
|
||||
possession = possession ?? defender?.getPossession(possessionId) ?? undefined;
|
||||
|
||||
if (!possession) {
|
||||
ui.notifications.warn("Une erreur s'est produite : Aucune possession trouvée !!")
|
||||
return
|
||||
}
|
||||
possession = duplicate(possession)
|
||||
// Update for draconic roll
|
||||
let rollData = {
|
||||
mode: "conjuration",
|
||||
isECNIDefender: defender.type == "entite",
|
||||
possession: possession,
|
||||
attacker: attacker,
|
||||
defender: defender,
|
||||
competence: defender.getDraconicOuPossession(),
|
||||
selectedCarac: defender.system.carac.reve,
|
||||
forceCarac: { 'reve-actuel': { label: "Rêve Actuel", value: defender.getReveActuel() } }
|
||||
}
|
||||
rollData.competence.system.defaut_carac = 'reve-actuel'
|
||||
|
||||
await RdDPossession.$rollDefensePossession(defender, rollData);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async $rollAttaquePossession(attacker, rollData, isNouvelle = false) {
|
||||
const dialog = await RdDRoll.create(attacker, rollData,
|
||||
{ html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html' },
|
||||
{
|
||||
name: 'jet-possession',
|
||||
label: rollData.isECNIDefender ? 'Conjurer la possession' : 'Possession',
|
||||
callbacks: [
|
||||
{ condition: r => (r.rolled.isSuccess), action: async (r) => await RdDPossession.$onRollPossession(r, true, isNouvelle) },
|
||||
{ condition: r => (r.rolled.isEchec), action: async (r) => await RdDPossession.$onRollPossession(r, false, isNouvelle) },
|
||||
]
|
||||
});
|
||||
dialog.render(true);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async $onRollPossession(rollData, isSuccess, isNouvelle = false) {
|
||||
rollData.possession.isSuccess = isSuccess;
|
||||
RdDPossession.$updateEtatPossession(rollData.possession);
|
||||
if (isNouvelle) {
|
||||
// Creer la possession sur le defenseur
|
||||
rollData.defender.createEmbeddedDocuments('Item', [rollData.possession.toObject()])
|
||||
}
|
||||
await RdDResolutionTable.displayRollData(rollData, rollData.attacker, 'chat-resultat-possession.html');
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async $rollDefensePossession(defender, rollData) {
|
||||
const dialog = await RdDRoll.create(defender, rollData,
|
||||
{ html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-defense-possession.html' },
|
||||
{
|
||||
name: 'conjurer',
|
||||
label: 'Conjurer une Possession',
|
||||
callbacks: [
|
||||
{ action: async (r) => await RdDPossession.$onRollConjuration(r) }
|
||||
]
|
||||
}
|
||||
);
|
||||
dialog.render(true);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async $onRollConjuration(rollData) {
|
||||
let actor = game.actors.get(rollData.possession.system.possedeid)
|
||||
if (!rollData.rolled.isSuccess) {
|
||||
if (rollData.isECNIDefender) {
|
||||
rollData.possession.system.compteur--
|
||||
} else {
|
||||
rollData.possession.system.compteur++
|
||||
}
|
||||
let update = { _id: rollData.possession._id, "system.compteur": rollData.possession.system.compteur }
|
||||
await actor.updateEmbeddedDocuments('Item', [update])
|
||||
}
|
||||
|
||||
RdDPossession.$updateEtatPossession(rollData.possession)
|
||||
|
||||
await RdDResolutionTable.displayRollData(rollData,rollData.defender, 'chat-resultat-possession.html')
|
||||
if (rollData.possession.isPosseder || rollData.possession.isConjurer) {
|
||||
// conjuration
|
||||
actor.deleteEmbeddedDocuments("Item", [rollData.possession._id])
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static $updateEtatPossession(possession) {
|
||||
static updateEtatPossession(possession) {
|
||||
possession.ptsConjuration = 0
|
||||
possession.ptsPossession = 0
|
||||
console.log("Possession", possession)
|
||||
if (possession.system.compteur > 0) {
|
||||
possession.ptsPossession = possession.system.compteur
|
||||
if (possession.data.compteur > 0) {
|
||||
possession.ptsPossession = possession.data.compteur
|
||||
}
|
||||
if (possession.system.compteur < 0) {
|
||||
possession.ptsConjuration = Math.abs(possession.system.compteur)
|
||||
if (possession.data.compteur < 0) {
|
||||
possession.ptsConjuration = Math.abs(possession.data.compteur)
|
||||
}
|
||||
possession.isPosseder = false
|
||||
possession.isConjurer = false
|
||||
@ -181,15 +48,122 @@ export class RdDPossession {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async createPossession(attacker, defender) {
|
||||
return await Item.create({
|
||||
name: "Possession en cours de " + attacker.name, type: 'possession',
|
||||
img: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp",
|
||||
system: { description: "", typepossession: attacker.name, possede: false, possessionid: randomID(16), possesseurid: attacker.id, possedeid: defender.id, date: 0, compteur: 0 }
|
||||
static async resultConjuration(rollData) {
|
||||
let actor = game.actors.get(rollData.possession.data.possedeid)
|
||||
if (!rollData.rolled.isSuccess) {
|
||||
if (rollData.isECNIDefender) {
|
||||
rollData.possession.data.compteur--
|
||||
} else {
|
||||
rollData.possession.data.compteur++
|
||||
}
|
||||
let update = { _id: rollData.possession._id, "data.compteur": rollData.possession.data.compteur }
|
||||
await actor.updateEmbeddedDocuments('Item', [update])
|
||||
}
|
||||
|
||||
this.updateEtatPossession(rollData.possession)
|
||||
await RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-possession.html')
|
||||
if (rollData.possession.isPosseder || rollData.possession.isConjurer) {
|
||||
actor.deleteEmbeddedDocuments("Item", [rollData.possession._id])
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async onDefensePossession(attackerId, defenderId, possessionId) {
|
||||
let attacker = game.actors.get(attackerId)
|
||||
let defender = game.actors.get(defenderId)
|
||||
let possession = attacker.getPossession(possessionId) ?? defender.getPossession(possessionId) ;
|
||||
if (!possession) {
|
||||
ui.notifications.warn("Une erreur s'est produite : Aucune possession trouvée !!")
|
||||
return
|
||||
}
|
||||
// Update for draconic roll
|
||||
let rollData = {
|
||||
mode: "conjuration",
|
||||
isECNIDefender: defender.type == "entite",
|
||||
possession: duplicate(possession),
|
||||
attacker: attacker,
|
||||
defender: defender,
|
||||
competence: defender.getDraconicOuPossession(),
|
||||
selectedCarac: defender.data.data.carac.reve,
|
||||
forceCarac: { 'reve-actuel': { label: "Rêve Actuel", value: defender.getReveActuel() } }
|
||||
}
|
||||
rollData.competence.data.defaut_carac = 'reve-actuel'
|
||||
|
||||
|
||||
const dialog = await RdDRoll.create(defender, rollData,
|
||||
{
|
||||
html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-defense-possession.html',
|
||||
options: { height: 450 }
|
||||
},
|
||||
{
|
||||
temporary: true
|
||||
})
|
||||
name: 'conjurer',
|
||||
label: 'Conjurer une Possession',
|
||||
callbacks: [
|
||||
{ action: async r => await this.resultConjuration(r) }
|
||||
]
|
||||
}
|
||||
);
|
||||
dialog.render(true)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async onAttaquePossession(attacker, competence, possession = undefined) {
|
||||
const target = RdDCombat.getTarget()
|
||||
if (target == undefined) {
|
||||
ui.notifications.warn((game.user.targets?.size ?? 0) > 1
|
||||
? "Vous devez choisir <strong>une seule</strong> cible à posséder!"
|
||||
: "Vous devez choisir une cible à posséder!");
|
||||
return;
|
||||
}
|
||||
|
||||
const defender = target.actor;
|
||||
possession = duplicate(possession ?? this.searchPossessionFromEntite(attacker, defender) ??(await this.createPossession(attacker, defender)));
|
||||
|
||||
this.updateEtatPossession(possession)
|
||||
let rollData = {
|
||||
mode: "possession",
|
||||
isECNIDefender: defender.type == "entite",
|
||||
competence: competence,
|
||||
possession: possession,
|
||||
attacker: attacker,
|
||||
defender: defender
|
||||
};
|
||||
if (attacker.isCreature()) {
|
||||
RdDItemCompetenceCreature.setRollDataCreature(rollData)
|
||||
}
|
||||
|
||||
const dialog = await RdDRoll.create(attacker, rollData,
|
||||
{
|
||||
html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html',
|
||||
options: { height: 540 }
|
||||
}, {
|
||||
name: 'jet-possession',
|
||||
label: rollData.isECNIDefender ? 'Conjurer la possession' : 'Possession',
|
||||
callbacks: [
|
||||
{ condition: r => (r.rolled.isSuccess), action: async r => await this._onRollPossession(r, true) },
|
||||
{ condition: r => (r.rolled.isEchec), action: async r => await this._onRollPossession(r, false) },
|
||||
]
|
||||
});
|
||||
dialog.render(true)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async _onRollPossession(rollData, isSuccess) {
|
||||
rollData.possession.isSuccess = isSuccess;
|
||||
this.updateEtatPossession(rollData.possession);
|
||||
await RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-possession.html');
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async createPossession(attacker, defender) {
|
||||
let possessionData = {
|
||||
name: "Possession en cours de " + attacker.name, type: 'possession',
|
||||
img: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp",
|
||||
data: { description: "", typepossession: attacker.name, possede: false, possessionid: randomID(16), possesseurid: attacker.data._id, possedeid: defender.data._id, date: 0, compteur: 0 }
|
||||
}
|
||||
// Creates only the possession on the personnage side
|
||||
let poss = await defender.createEmbeddedDocuments('Item', [possessionData])
|
||||
return duplicate(poss[0])
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import { ChatUtility } from "./chat-utility.js";
|
||||
import { Misc } from "./misc.js";
|
||||
import { RdDDice } from "./rdd-dice.js";
|
||||
import { ReglesOptionelles } from "./settings/regles-optionelles.js";
|
||||
import { ReglesOptionelles } from "./regles-optionelles.js";
|
||||
|
||||
/**
|
||||
* difficultés au delà de -10
|
||||
@ -14,7 +14,7 @@ const levelDown = [
|
||||
{ level: -15, score: 1, norm: 1, sign: 0, part: 0, epart: 2, etotal: 10 },
|
||||
{ level: -16, score: 1, norm: 1, sign: 0, part: 0, epart: 0, etotal: 2 }
|
||||
];
|
||||
const levelImpossible = { score: 0, norm: 0, sign: 0, part: 0, epart: 0, etotal: 1 };
|
||||
const levelImpossible = { score: 0, norm:0, sign: 0, part: 0, epart: 0, etotal: 1 };
|
||||
|
||||
const reussites = [
|
||||
{ code: "etotal", isPart: false, isSign: false, isSuccess: false, isEchec: true, isEPart: true, isETotal: true, ptTache: -4, ptQualite: -6, quality: "Echec total", condition: (target, roll) => roll >= target.etotal && roll <= 100 },
|
||||
@ -42,44 +42,6 @@ export class RdDResolutionTable {
|
||||
return table;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static computeChances(carac, level) {
|
||||
if (level < -16) {
|
||||
return levelImpossible;
|
||||
}
|
||||
if (level < -10) {
|
||||
return levelDown.find(it => it.level == level);
|
||||
}
|
||||
const percentage = RdDResolutionTable.computePercentage(carac, level);
|
||||
return this._computeCell(level, percentage);
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static _computeRow(caracValue) {
|
||||
let dataRow = [
|
||||
this._computeCell(-10, Math.max(Math.floor(caracValue / 4), 1)),
|
||||
this._computeCell(-9, Math.max(Math.floor(caracValue / 2), 1))
|
||||
]
|
||||
for (var diff = -8; diff <= 22; diff++) {
|
||||
dataRow[diff + 10] = this._computeCell(diff, RdDResolutionTable.computePercentage(caracValue, diff));
|
||||
}
|
||||
return dataRow;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static _computeCell(niveau, percentage) {
|
||||
return {
|
||||
niveau: niveau,
|
||||
score: percentage,
|
||||
norm: Math.min(99, percentage),
|
||||
sign: this._reussiteSignificative(percentage),
|
||||
part: this._reussitePart(percentage),
|
||||
epart: this._echecParticulier(percentage),
|
||||
etotal: this._echecTotal(percentage)
|
||||
};
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getResultat(code) {
|
||||
let resultat = reussites.find(r => code == r.code);
|
||||
@ -89,6 +51,17 @@ export class RdDResolutionTable {
|
||||
return resultat;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static explain(rolled) {
|
||||
let message = "<br>Jet : <strong>" + rolled.roll + "</strong> sur " + rolled.score + "% ";
|
||||
if (rolled.caracValue != null && rolled.finalLevel != null) {
|
||||
message += (rolled.diviseurSignificative > 1 ? `(1/${rolled.diviseurSignificative} de ` : "(")
|
||||
+ rolled.caracValue + " à " + Misc.toSignedString(rolled.finalLevel) + ") ";
|
||||
}
|
||||
message += '<strong>' + rolled.quality + '</strong>'
|
||||
return message;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async displayRollData(rollData, actor = undefined, template = 'chat-resultat-general.html') {
|
||||
return await ChatUtility.createChatWithRollMode(actor?.userName ?? game.user.name, {
|
||||
@ -109,8 +82,8 @@ export class RdDResolutionTable {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async roll(caracValue, finalLevel, rollData = {}) {
|
||||
let chances = duplicate(this.computeChances(caracValue, finalLevel));
|
||||
static async roll(caracValue, finalLevel, rollData = {}){
|
||||
let chances = this.computeChances(caracValue, finalLevel);
|
||||
this._updateChancesWithBonus(chances, rollData.bonus, finalLevel);
|
||||
this._updateChancesFactor(chances, rollData.diviseurSignificative);
|
||||
chances.showDice = rollData.showDice;
|
||||
@ -122,7 +95,7 @@ export class RdDResolutionTable {
|
||||
rolled.bonus = rollData.bonus;
|
||||
rolled.factorHtml = Misc.getFractionHtml(rollData.diviseurSignificative);
|
||||
|
||||
if (ReglesOptionelles.isUsing("afficher-colonnes-reussite")) {
|
||||
if (ReglesOptionelles.isUsing("afficher-colonnes-reussite")){
|
||||
rolled.niveauNecessaire = this.findNiveauNecessaire(caracValue, rolled.roll);
|
||||
rolled.ajustementNecessaire = rolled.niveauNecessaire - finalLevel;
|
||||
}
|
||||
@ -130,39 +103,28 @@ export class RdDResolutionTable {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static findNiveauNecessaire(carac, rolled) {
|
||||
if (carac == 0) {
|
||||
return NaN;
|
||||
static findNiveauNecessaire(caracValue, rollValue) {
|
||||
for (let cell of this.resolutionTable[caracValue]) {
|
||||
if ( rollValue <= cell.norm) {
|
||||
return cell.niveau;
|
||||
}
|
||||
}
|
||||
if (rolled >= carac){
|
||||
const upper = Math.ceil(rolled/carac);
|
||||
return 2*upper -10
|
||||
}
|
||||
if (rolled > Math.floor(carac/2)) {
|
||||
return -8
|
||||
}
|
||||
if (rolled > Math.floor(carac/4)) {
|
||||
return -9
|
||||
}
|
||||
if (rolled > 1) {
|
||||
return -10
|
||||
}
|
||||
return -11;
|
||||
return 16; // Dummy default
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static _updateChancesFactor(chances, diviseur) {
|
||||
if (chances.level > -11 && diviseur && diviseur > 1) {
|
||||
let newScore = Math.floor(chances.score / diviseur);
|
||||
mergeObject(chances, this._computeCell(undefined, newScore), { overwrite: true });
|
||||
mergeObject(chances, this._computeCell(null, newScore), { overwrite: true });
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static _updateChancesWithBonus(chances, bonus, finalLevel) {
|
||||
if (bonus && finalLevel > -11) {
|
||||
if (bonus && finalLevel>-11) {
|
||||
let newScore = Number(chances.score) + bonus;
|
||||
mergeObject(chances, this._computeCell(undefined, newScore), { overwrite: true });
|
||||
mergeObject(chances, this._computeCell(null, newScore), { overwrite: true });
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,19 +142,24 @@ export class RdDResolutionTable {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async rollChances(chances, diviseur, forceDiceResult = -1) {
|
||||
chances.forceDiceResult = forceDiceResult <= 0 || forceDiceResult > 100 ? undefined : { total: forceDiceResult };
|
||||
chances.roll = await RdDDice.rollTotal("1d100", chances);
|
||||
if (forceDiceResult <= 0 || forceDiceResult > 100) {
|
||||
forceDiceResult = -1;
|
||||
}
|
||||
chances.roll = await RdDDice.rollTotal((forceDiceResult == -1) ? "1d100" : `${forceDiceResult}`, chances);
|
||||
mergeObject(chances, this.computeReussite(chances, chances.roll, diviseur), { overwrite: true });
|
||||
return chances;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static computePercentage(carac, diff) {
|
||||
if (diff < -16) return 0
|
||||
if (diff < -10) return 1
|
||||
if (diff == -10) return Math.max(Math.floor(carac / 4), 1)
|
||||
if (diff == -9) return Math.max(Math.floor(carac / 2), 1)
|
||||
return Math.max(Math.floor(carac * (diff + 10) / 2), 1);
|
||||
static computeChances(caracValue, difficulte) {
|
||||
if (difficulte < -16) {
|
||||
return duplicate(levelImpossible);
|
||||
}
|
||||
if (difficulte < -10) {
|
||||
return duplicate(levelDown.find(levelData => levelData.level == difficulte));
|
||||
}
|
||||
console.log("DATA :", caracValue, difficulte)
|
||||
return duplicate(RdDResolutionTable.resolutionTable[caracValue][difficulte + 10]);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -200,7 +167,7 @@ export class RdDResolutionTable {
|
||||
if (rollData.selectedCarac?.label.toLowerCase().includes('chance')) {
|
||||
return true;
|
||||
}
|
||||
if (rollData.selectedSort?.system.isrituel) {
|
||||
if (rollData.selectedSort?.data.isrituel) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -249,6 +216,31 @@ export class RdDResolutionTable {
|
||||
return reussite;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static _computeRow(caracValue) {
|
||||
let dataRow = [
|
||||
this._computeCell(-10, Math.max(Math.floor(caracValue / 4), 1)),
|
||||
this._computeCell(-9, Math.max(Math.floor(caracValue / 2), 1))
|
||||
]
|
||||
for (var diff = -8; diff <= 22; diff++) {
|
||||
dataRow[diff + 10] = this._computeCell(diff, Math.max(Math.floor(caracValue * (diff + 10) / 2), 1));
|
||||
}
|
||||
return dataRow;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static _computeCell(niveau, percentage) {
|
||||
return {
|
||||
niveau: niveau,
|
||||
score: percentage,
|
||||
norm: Math.min(99, percentage),
|
||||
sign: this._reussiteSignificative(percentage),
|
||||
part: this._reussitePart(percentage),
|
||||
epart: this._echecParticulier(percentage),
|
||||
etotal: this._echecTotal(percentage)
|
||||
};
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static _reussiteSignificative(percentage) {
|
||||
return Math.floor(percentage / 2);
|
||||
@ -272,34 +264,92 @@ export class RdDResolutionTable {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static subTable(carac, level, delta = { carac: 2, level: 5}) {
|
||||
return {
|
||||
carac,
|
||||
level,
|
||||
minCarac: carac - (delta?.carac ?? 2),
|
||||
maxCarac: carac + (delta?.carac ?? 2),
|
||||
minLevel: level - (delta?.level ?? 5),
|
||||
maxLevel: level + (delta?.level ?? 5)
|
||||
};
|
||||
static buildHTMLResults(caracValue, levelValue) {
|
||||
if (caracValue == undefined || isNaN(caracValue)) caracValue = 10;
|
||||
if (levelValue == undefined || isNaN(levelValue)) levelValue = 0;
|
||||
|
||||
let cell = this.computeChances(caracValue, levelValue);
|
||||
cell.epart = cell.epart > 99 ? 'N/A' : cell.epart;
|
||||
cell.etotal = cell.etotal > 100 ? 'N/A' : cell.etotal;
|
||||
cell.score = Math.min(cell.score, 99);
|
||||
|
||||
return `
|
||||
<span class="table-proba-reussite competence-label">
|
||||
Particulière: <span class="rdd-roll-part">${cell.part}</span>
|
||||
- Significative: <span class="rdd-roll-sign">${cell.sign}</span>
|
||||
- Réussite: <span class="rdd-roll-norm">${cell.score}</span>
|
||||
- Echec Particulier: <span class="rdd-roll-epart">${cell.epart}</span>
|
||||
- Echec Total: <span class="rdd-roll-etotal">${cell.etotal}</span>
|
||||
</span>
|
||||
`
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async buildHTMLTable({ carac: carac, level: level, minCarac = 1, maxCarac = 21, minLevel = -10, maxLevel = 11 }) {
|
||||
let colonnes = maxLevel - minLevel;
|
||||
minCarac = Math.max(minCarac, 1);
|
||||
maxCarac = Math.min(maxCarac, minCarac + 20);
|
||||
minLevel = Math.max(minLevel, -10);
|
||||
maxLevel = Math.max(Math.min(maxLevel, 30), minLevel + colonnes);
|
||||
return await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/resolution-table.html', {
|
||||
carac: carac,
|
||||
difficulte: level,
|
||||
min: minLevel,
|
||||
rows: RdDResolutionTable.incrementalArray(minCarac, maxCarac),
|
||||
cols: RdDResolutionTable.incrementalArray(minLevel, maxLevel)
|
||||
});
|
||||
static buildHTMLTableExtract(caracValue, levelValue) {
|
||||
return this.buildHTMLTable(caracValue, levelValue, caracValue - 2, caracValue + 2, levelValue - 5, levelValue + 5)
|
||||
}
|
||||
static incrementalArray(min, max) {
|
||||
return Array.from(Array(max-min+1).keys()).map(i=>i+min)
|
||||
|
||||
static buildHTMLTable(caracValue, levelValue, minCarac = 1, maxCarac = 21, minLevel = -10, maxLevel = 11) {
|
||||
return this._buildHTMLTable(caracValue, levelValue, minCarac, maxCarac, minLevel, maxLevel)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static _buildHTMLTable(caracValue, levelValue, minCarac, maxCarac, minLevel, maxLevel) {
|
||||
let countColonnes = maxLevel - minLevel;
|
||||
minCarac = Math.max(minCarac, 1);
|
||||
maxCarac = Math.min(maxCarac, caracMaximumResolution);
|
||||
minLevel = Math.max(minLevel, -10);
|
||||
maxLevel = Math.max(Math.min(maxLevel, 22), minLevel + countColonnes);
|
||||
|
||||
let table = $("<table class='table-resolution'/>")
|
||||
.append(this._buildHTMLHeader(RdDResolutionTable.resolutionTable[0], minLevel, maxLevel));
|
||||
|
||||
for (var rowIndex = minCarac; rowIndex <= maxCarac; rowIndex++) {
|
||||
table.append(this._buildHTMLRow(RdDResolutionTable.resolutionTable[rowIndex], rowIndex, caracValue, levelValue, minLevel, maxLevel));
|
||||
}
|
||||
table.append("</table>");
|
||||
return table;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static _buildHTMLHeader(dataRow, minLevel, maxLevel) {
|
||||
let tr = $("<tr/>");
|
||||
|
||||
if (minLevel > -8) {
|
||||
tr.append($("<th class='table-resolution-level'/>").text("-8"))
|
||||
}
|
||||
if (minLevel > -7) {
|
||||
tr.append($("<th class='table-resolution-level'/>").text("..."));
|
||||
}
|
||||
for (let difficulte = minLevel; difficulte <= maxLevel; difficulte++) {
|
||||
tr.append($("<th class='table-resolution-level'/>").text(Misc.toSignedString(difficulte)));
|
||||
}
|
||||
return tr;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static _buildHTMLRow(dataRow, rowIndex, caracValue, levelValue, minLevel, maxLevel) {
|
||||
let tr = $("<tr/>");
|
||||
let max = maxLevel;
|
||||
|
||||
if (minLevel > -8) {
|
||||
let score = dataRow[-8 + 10].score;
|
||||
tr.append($("<td class='table-resolution-carac'/>").text(score))
|
||||
}
|
||||
if (minLevel > -7) {
|
||||
tr.append($("<td/>"))
|
||||
}
|
||||
for (let difficulte = minLevel; difficulte <= max; difficulte++) {
|
||||
let td = $("<td/>");
|
||||
let score = dataRow[difficulte + 10].score;
|
||||
if (rowIndex == caracValue && levelValue == difficulte) {
|
||||
td.addClass('table-resolution-target');
|
||||
} else if (difficulte == -8) {
|
||||
td.addClass('table-resolution-carac');
|
||||
}
|
||||
tr.append(td.text(score));
|
||||
}
|
||||
return tr;
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
import { ENTITE_BLURETTE, ENTITE_INCARNE } from "./constants.js";
|
||||
import { RdDUtility } from "./rdd-utility.js";
|
||||
import { ENTITE_BLURETTE, ENTITE_INCARNE, ENTITE_NONINCARNE } from "./constants.js";
|
||||
|
||||
/**
|
||||
* Extend the base Dialog entity by defining a custom window to perform roll.
|
||||
@ -7,39 +6,34 @@ import { RdDUtility } from "./rdd-utility.js";
|
||||
*/
|
||||
export class RdDEncaisser extends Dialog {
|
||||
|
||||
static async encaisser(actor) {
|
||||
let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-roll-encaisser.html',
|
||||
{ ajustementsEncaissement: RdDUtility.getAjustementsEncaissement() }
|
||||
);
|
||||
new RdDEncaisser(html, actor).render(true);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(html, actor) {
|
||||
let dialogConf = {
|
||||
title: "Jet d'Encaissement",
|
||||
content: html,
|
||||
}
|
||||
|
||||
if (!actor.isEntite()) {
|
||||
dialogConf.default = "mortel";
|
||||
dialogConf.buttons = {
|
||||
// Common conf
|
||||
let buttons = {};
|
||||
if (!actor.isEntite()){
|
||||
buttons = {
|
||||
"mortel": { label: "Mortel", callback: html => this.performEncaisser("mortel") },
|
||||
"non-mortel": { label: "Non-mortel", callback: html => this.performEncaisser("non-mortel") },
|
||||
"sonne": { label: "Sonné", callback: html => this.actor.setSonne() },
|
||||
};
|
||||
}
|
||||
else if (actor.isEntite([ENTITE_BLURETTE, ENTITE_INCARNE])) {
|
||||
dialogConf.default = "cauchemar"
|
||||
dialogConf.buttons = {
|
||||
"cauchemar": { label: "Cauchemar", callback: html => this.performEncaisser("cauchemar") }
|
||||
else if (actor.isEntite([ENTITE_BLURETTE, ENTITE_INCARNE])){
|
||||
buttons = {
|
||||
"cauchemar": { label: "cauchemar", callback: html => this.performEncaisser("cauchemar") }
|
||||
}
|
||||
}
|
||||
|
||||
let dialogConf = {
|
||||
title: "Jet d'Encaissement",
|
||||
content: html,
|
||||
buttons: buttons,
|
||||
default: "mortel"
|
||||
}
|
||||
|
||||
let dialogOptions = {
|
||||
classes: ["rdd-roll-dialog"],
|
||||
classes: ["rdddialog"],
|
||||
width: 320,
|
||||
height: 'fit-content'
|
||||
height: 240
|
||||
}
|
||||
|
||||
// Select proper roll dialog template and stuff
|
||||
@ -50,29 +44,35 @@ export class RdDEncaisser extends Dialog {
|
||||
this.encaisserSpecial = "aucun";
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
this.html = html;
|
||||
|
||||
this.html.find('[name="modificateurDegats"]').val("0");
|
||||
this.html.find('[name="modificateurDegats"]').change((event) => {
|
||||
this.modifier = event.currentTarget.value; // Update the selected bonus/malus
|
||||
});
|
||||
this.html.find('[name="encaisserSpecial"]').change((event) => {
|
||||
this.encaisserSpecial = event.currentTarget.value; // Update the selected bonus/malus
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
performEncaisser(mortalite) {
|
||||
this.actor.encaisserDommages({
|
||||
dmg: {
|
||||
total: Number(this.modifier),
|
||||
ajustement: Number(this.modifier),
|
||||
encaisserSpecial: this.encaisserSpecial,
|
||||
loc: { result: 0, label: "" },
|
||||
mortalite: mortalite
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
// Setup everything onload
|
||||
$(function () {
|
||||
$("#modificateurDegats").val("0");
|
||||
});
|
||||
|
||||
html.find('#modificateurDegats').change((event) => {
|
||||
this.modifier = event.currentTarget.value; // Update the selected bonus/malus
|
||||
});
|
||||
html.find('#encaisserSpecial').change((event) => {
|
||||
this.encaisserSpecial = event.currentTarget.value; // Update the selected bonus/malus
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,33 +13,47 @@ export class RdDRollDialogEthylisme extends Dialog {
|
||||
title: "Test d'éthylisme",
|
||||
content: html,
|
||||
default: "rollButton",
|
||||
buttons: { "rollButton": { label: "Test d'éthylisme", callback: html => onRoll(this.rollData) } }
|
||||
buttons: { "rollButton": { label: "Test d'éthylisme", callback: html => this.onButton(html) } }
|
||||
};
|
||||
let dialogOptions = { classes: ["rdd-roll-dialog"], width: 400, height: 'fit-content', 'z-index': 99999 }
|
||||
let dialogOptions = { classes: ["rdddialog"], width: 400, height: 270, 'z-index': 99999 }
|
||||
super(dialogConf, dialogOptions)
|
||||
|
||||
//console.log("ETH", rollData);
|
||||
this.onRoll = onRoll;
|
||||
this.rollData = rollData;
|
||||
this.actor = actor;
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
this.html = html;
|
||||
this.bringToTop();
|
||||
|
||||
this.html.find(".force-alcool").change((event) => {
|
||||
this.rollData.forceAlcool = Misc.toInt(event.currentTarget.value);
|
||||
this.updateRollResult();
|
||||
});
|
||||
|
||||
this.html.find(".force-alcool").val(Misc.toInt(this.rollData.forceAlcool));
|
||||
this.updateRollResult();
|
||||
async onButton(html) {
|
||||
this.onRoll(this.rollData);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
this.bringToTop(); // Ensure top level
|
||||
// Get the rollData stuff
|
||||
var rollData = this.rollData;
|
||||
var dialog = this;
|
||||
|
||||
// Setup everything onload
|
||||
$(function () {
|
||||
$("#forceAlcool").val(Misc.toInt(rollData.forceAlcool));
|
||||
dialog.updateRollResult();
|
||||
});
|
||||
|
||||
// Update !
|
||||
html.find('#forceAlcool').change((event) => {
|
||||
rollData.forceAlcool = Misc.toInt(event.currentTarget.value); // Update the selected bonus/malus
|
||||
dialog.updateRollResult();
|
||||
});
|
||||
}
|
||||
async updateRollResult() {
|
||||
this.html.find(".roll-ethylisme").text(this.rollData.vie + " / " + Misc.toSignedString(Number(this.rollData.etat) + Number(this.rollData.forceAlcool) + this.rollData.diffNbDoses));
|
||||
this.html.find(".table-resolution").remove();
|
||||
|
||||
// Mise à jour valeurs
|
||||
$("#roll-param").text(this.rollData.vie + " / " + Misc.toSignedString(Number(this.rollData.etat) + Number(this.rollData.forceAlcool) + this.rollData.diffNbDoses));
|
||||
$(".table-resolution").remove();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,19 +9,12 @@ const titleTableDeResolution = 'Table de résolution';
|
||||
/* -------------------------------------------- */
|
||||
export class RdDRollResolutionTable extends Dialog {
|
||||
|
||||
static resolutionTable = undefined;
|
||||
/* -------------------------------------------- */
|
||||
static async open() {
|
||||
if (RdDRollResolutionTable.resolutionTable == undefined) {
|
||||
const rollData = {}
|
||||
RdDRollResolutionTable._setDefaultOptions(rollData);
|
||||
let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-roll-resolution.html', rollData);
|
||||
RdDRollResolutionTable.resolutionTable = new RdDRollResolutionTable(rollData, html);
|
||||
RdDRollResolutionTable.resolutionTable.render(true);
|
||||
}
|
||||
else{
|
||||
RdDRollResolutionTable.resolutionTable.bringToTop();
|
||||
}
|
||||
static async open(rollData = {}) {
|
||||
RdDRollResolutionTable._setDefaultOptions(rollData);
|
||||
let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-roll-resolution.html', rollData);
|
||||
const dialog = new RdDRollResolutionTable(rollData, html);
|
||||
dialog.render(true);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -60,40 +53,11 @@ export class RdDRollResolutionTable extends Dialog {
|
||||
'lancer-fermer': { label: 'Lancer les dés et fermer', callback: html => this.onLancerFermer() }
|
||||
}
|
||||
};
|
||||
super(conf, { classes: ["rdd-roll-dialog"], top: 50, width: 'fit-content', height: 'fit-content', 'z-index': 99999 });
|
||||
super(conf, { classes: ["rdddialog"], width: 800, height: 800, 'z-index': 99999 });
|
||||
|
||||
this.rollData = rollData;
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
this.html = html;
|
||||
this.bringToTop();
|
||||
|
||||
|
||||
this.html.find("[name='diffLibre']").val(Misc.toInt(this.rollData.diffLibre));
|
||||
this.html.find("[name='diffConditions']").val(Misc.toInt(this.rollData.diffConditions));
|
||||
this.updateRollResult();
|
||||
|
||||
this.html.find('.lancer-table-resolution').click((event) => {
|
||||
this.onLancer();
|
||||
});
|
||||
// Update !
|
||||
this.html.find("[name='diffLibre']").change((event) => {
|
||||
this.rollData.diffLibre = Misc.toInt(event.currentTarget.value);
|
||||
this.updateRollResult();
|
||||
});
|
||||
this.html.find("[name='diffConditions']").change((event) => {
|
||||
this.rollData.diffConditions = Misc.toInt(event.currentTarget.value);
|
||||
this.updateRollResult();
|
||||
});
|
||||
this.html.find("[name='carac']").change((event) => {
|
||||
let caracKey = event.currentTarget.value;
|
||||
this.rollData.selectedCarac = this.rollData.carac[caracKey];
|
||||
this.updateRollResult();
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async onLancer() {
|
||||
await RdDResolutionTable.rollData(this.rollData);
|
||||
@ -108,36 +72,65 @@ export class RdDRollResolutionTable extends Dialog {
|
||||
await RdDResolutionTable.displayRollData(this.rollData);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
this.bringToTop();
|
||||
|
||||
var dialog = this;
|
||||
|
||||
// Setup everything onload
|
||||
function onLoad(){
|
||||
$("#diffLibre").val(Misc.toInt(dialog.rollData.diffLibre));
|
||||
$("#diffConditions").val(Misc.toInt(dialog.rollData.diffConditions));
|
||||
dialog.updateRollResult();
|
||||
}
|
||||
$(function () { onLoad();});
|
||||
html.find('#lancer').click((event) => {
|
||||
this.onLancer();
|
||||
});
|
||||
// Update !
|
||||
html.find('#diffLibre').change((event) => {
|
||||
this.rollData.diffLibre = Misc.toInt(event.currentTarget.value);
|
||||
this.updateRollResult();
|
||||
});
|
||||
html.find('#diffConditions').change((event) => {
|
||||
this.rollData.diffConditions = Misc.toInt(event.currentTarget.value);
|
||||
this.updateRollResult();
|
||||
});
|
||||
html.find('#carac').change((event) => {
|
||||
let caracKey = event.currentTarget.value;
|
||||
this.rollData.selectedCarac = this.rollData.carac[caracKey];
|
||||
this.updateRollResult();
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async updateRollResult() {
|
||||
let rollData = this.rollData;
|
||||
rollData.caracValue = parseInt(rollData.selectedCarac.value)
|
||||
rollData.finalLevel = this._computeFinalLevel(rollData);
|
||||
|
||||
const htmlTable = await RdDResolutionTable.buildHTMLTable({
|
||||
carac: rollData.caracValue,
|
||||
level: rollData.finalLevel,
|
||||
maxCarac: 20,
|
||||
maxLevel: 10
|
||||
});
|
||||
|
||||
// Mise à jour valeurs
|
||||
this.html.find("[name='carac']").val(rollData.caracValue);
|
||||
this.html.find(".roll-param-resolution").text(rollData.selectedCarac.value + " / " + Misc.toSignedString(rollData.finalLevel));
|
||||
this.html.find("div.placeholder-resolution").empty().append(htmlTable)
|
||||
|
||||
$("#carac").val(rollData.caracValue);
|
||||
$("#roll-param").text(rollData.selectedCarac.value + " / " + Misc.toSignedString(rollData.finalLevel));
|
||||
$(".table-resolution").remove();
|
||||
$(".table-proba-reussite").remove();
|
||||
$("#tableResolution").append(RdDResolutionTable.buildHTMLTable(rollData.caracValue, rollData.finalLevel));
|
||||
$("#tableProbaReussite").append(RdDResolutionTable.buildHTMLResults(rollData.caracValue, rollData.finalLevel));
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_computeFinalLevel(rollData) {
|
||||
const diffConditions = Misc.toInt(rollData.diffConditions);
|
||||
const diffLibre = Misc.toInt(rollData.diffLibre);
|
||||
const diffLibre = this._computeDiffLibre(rollData);
|
||||
|
||||
return diffLibre + diffConditions;
|
||||
}
|
||||
|
||||
async close() {
|
||||
await super.close();
|
||||
RdDRollResolutionTable.resolutionTable = undefined;
|
||||
/* -------------------------------------------- */
|
||||
_computeDiffLibre(rollData) {
|
||||
return Misc.toInt(rollData.diffLibre);
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import { Misc } from "./misc.js";
|
||||
import { RdDBonus } from "./rdd-bonus.js";
|
||||
import { RdDCarac } from "./rdd-carac.js";
|
||||
import { RdDResolutionTable } from "./rdd-resolution-table.js";
|
||||
import { ReglesOptionelles } from "./settings/regles-optionelles.js";
|
||||
import { ReglesOptionelles } from "./regles-optionelles.js";
|
||||
|
||||
/**
|
||||
* Extend the base Dialog entity to select roll parameters
|
||||
@ -16,42 +16,48 @@ import { ReglesOptionelles } from "./settings/regles-optionelles.js";
|
||||
export class RdDRoll extends Dialog {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async create(actor, rollData, dialogConfig, action) {
|
||||
RdDRoll._ensureCorrectAction(action);
|
||||
static async create(actor, rollData, dialogConfig, ...actions) {
|
||||
|
||||
if (actor.isRollWindowsOpened()) {
|
||||
ui.notifications.warn("Vous avez déja une fenêtre de Test ouverte, il faut la fermer avant d'en ouvrir une autre.")
|
||||
return;
|
||||
}
|
||||
actor.setRollWindowsOpened(true);
|
||||
|
||||
RdDRoll._ensureCorrectActions(actions);
|
||||
RdDRoll._setDefaultOptions(actor, rollData);
|
||||
|
||||
const html = await renderTemplate(dialogConfig.html, rollData);
|
||||
|
||||
let options = { classes: ["rdd-roll-dialog"], width: 600, height: 'fit-content', 'z-index': 99999, close: html => {} };
|
||||
if (dialogConfig.close) {
|
||||
options.close = dialogConfig.close;
|
||||
let options = { classes: ["rdddialog"], width: 600, height: 500, 'z-index': 99999 };
|
||||
if (dialogConfig.options) {
|
||||
mergeObject(options, dialogConfig.options, { overwrite: true })
|
||||
}
|
||||
return new RdDRoll(actor, rollData, html, options, action);
|
||||
return new RdDRoll(actor, rollData, html, options, actions, dialogConfig.close);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static _setDefaultOptions(actor, rollData) {
|
||||
const actorData = Misc.data(actor);
|
||||
let defaultRollData = {
|
||||
alias: actor.name,
|
||||
ajustementsConditions: CONFIG.RDD.ajustementsConditions,
|
||||
difficultesLibres: CONFIG.RDD.difficultesLibres,
|
||||
etat: actor.getEtatGeneral(),
|
||||
moral: actor.getMoralTotal(), /* La valeur du moral pour les jets de volonté */
|
||||
carac: actor.system.carac,
|
||||
carac: actorData.data.carac,
|
||||
finalLevel: 0,
|
||||
diffConditions: 0,
|
||||
diffLibre: rollData.competence?.system.default_diffLibre ?? 0,
|
||||
perteMoralEchec: false, /* Pour l'affichage dans le chat */
|
||||
use: {
|
||||
moral: false, /* Est-ce que le joueur demande d'utiliser le moral ? Utile si le joueur change plusieurs fois de carac associée. */
|
||||
libre: true,
|
||||
conditions: true,
|
||||
surenc: actor.isSurenc(),
|
||||
encTotal: true
|
||||
},
|
||||
isMalusEncombrementTotal: RdDItemCompetence.isMalusEncombrementTotal(rollData.competence),
|
||||
diffLibre: rollData.competence?.data.default_diffLibre ?? 0,
|
||||
malusArmureValue: actor.getMalusArmure(),
|
||||
surencMalusFlag: actor.isPersonnage() ? (actorData.data.compteurs.surenc.value < 0) : false,
|
||||
surencMalusValue: actor.computeMalusSurEncombrement(),
|
||||
useMalusSurenc: false,
|
||||
useMoral: false, /* Est-ce que le joueur demande d'utiliser le moral ? Utile si le joueur change plusieurs fois de carac associée. */
|
||||
perteMoralEchec: false, /* Pour l'affichage dans le chat */
|
||||
use: { libre: true, conditions: true, surenc: false, encTotal: false },
|
||||
isMalusEncombrementTotal: RdDItemCompetence.isMalusEncombrementTotal(rollData.competence),
|
||||
useMalusEncTotal: false,
|
||||
encTotal: actor.getEncTotal(),
|
||||
ajustementAstrologique: actor.ajustementAstrologique(),
|
||||
surprise: actor.getSurprise(false),
|
||||
@ -60,8 +66,8 @@ export class RdDRoll extends Dialog {
|
||||
forceDiceResult: -1
|
||||
}
|
||||
// Mini patch :Ajout du rêve actuel
|
||||
if (actor.system.type == "personnage") {
|
||||
defaultRollData.carac["reve-actuel"] = actor.system.reve.reve
|
||||
if ( actorData.type == "personnage") {
|
||||
defaultRollData.carac["reve-actuel"] = actorData.data.reve.reve
|
||||
}
|
||||
|
||||
mergeObject(rollData, defaultRollData, { recursive: true, overwrite: false });
|
||||
@ -72,7 +78,6 @@ export class RdDRoll extends Dialog {
|
||||
|
||||
RollDataAjustements.calcul(rollData, actor);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getDiviseurSignificative(rollData) {
|
||||
let facteurSign = 1;
|
||||
@ -91,133 +96,158 @@ export class RdDRoll extends Dialog {
|
||||
return facteurSign;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static _ensureCorrectAction(action) {
|
||||
if (action.callbacks == undefined) {
|
||||
console.warn('No callback defined for ', action.name);
|
||||
action.callbacks = [{ action: r => console.warn(action.name, r) }];
|
||||
static _ensureCorrectActions(actions) {
|
||||
if (actions.length == 0) {
|
||||
throw 'No action defined';
|
||||
}
|
||||
actions.forEach(action => {
|
||||
if (action.callbacks == undefined) {
|
||||
action.callbacks = [{ action: r => console.log(action.name, r) }];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(actor, rollData, html, options, action) {
|
||||
constructor(actor, rollData, html, options, actions, close = undefined) {
|
||||
let conf = {
|
||||
title: action.label,
|
||||
title: actions[0].label,
|
||||
content: html,
|
||||
buttons: {
|
||||
"onAction": {
|
||||
label: action.label, callback: html => {
|
||||
this.rollData.canClose = true;
|
||||
this.onAction(action)
|
||||
}
|
||||
}
|
||||
},
|
||||
default: "onAction",
|
||||
close: options.close
|
||||
buttons: {},
|
||||
default: actions[0].name,
|
||||
close: close
|
||||
};
|
||||
for (let action of actions) {
|
||||
conf.buttons[action.name] = {
|
||||
label: action.label, callback: html => {
|
||||
this.rollData.canClose = true;
|
||||
this.onAction(action, html)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
super(conf, options);
|
||||
|
||||
this.actor = actor;
|
||||
this.rollData = rollData;
|
||||
}
|
||||
|
||||
close() {
|
||||
if (this.rollData.canClose) {
|
||||
this.actor.setRollWindowsOpened(false);
|
||||
return super.close();
|
||||
}
|
||||
ui.notifications.info("Vous devez faire ce jet de dés!");
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async onAction(action, html) {
|
||||
await RdDResolutionTable.rollData(this.rollData);
|
||||
console.log("RdDRoll -=>", this.rollData, this.rollData.rolled);
|
||||
this.actor.setRollWindowsOpened(false);
|
||||
if (action.callbacks)
|
||||
for (let callback of action.callbacks) {
|
||||
if (callback.condition == undefined || callback.condition(this.rollData)) {
|
||||
await callback.action(this.rollData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
this.html = html;
|
||||
|
||||
this.bringToTop();
|
||||
|
||||
console.log('RdDRoll.activateListeners', this.rollData);
|
||||
var dialog = this;
|
||||
|
||||
// Update html, according to rollData
|
||||
if (this.rollData.competence) {
|
||||
const defaut_carac = this.rollData.competence.system.defaut_carac
|
||||
// Set the default carac from the competence item
|
||||
this.rollData.selectedCarac = this.rollData.carac[defaut_carac];
|
||||
this.html.find("[name='carac']").val(defaut_carac);
|
||||
function onLoad() {
|
||||
let rollData = dialog.rollData;
|
||||
console.log(rollData);
|
||||
// Update html, according to data
|
||||
if (rollData.competence) {
|
||||
const defaut_carac = Misc.templateData(rollData.competence).defaut_carac;
|
||||
// Set the default carac from the competence item
|
||||
rollData.selectedCarac = rollData.carac[defaut_carac];
|
||||
$("#carac").val(defaut_carac);
|
||||
}
|
||||
if (rollData.selectedSort) {
|
||||
dialog.setSelectedSort(rollData.selectedSort);
|
||||
$(".draconic").val(rollData.selectedSort.data.listIndex); // Uniquement a la selection du sort, pour permettre de changer
|
||||
}
|
||||
RdDItemSort.setCoutReveReel(rollData.selectedSort);
|
||||
$("#diffLibre").val(Misc.toInt(rollData.diffLibre));
|
||||
$("#diffConditions").val(Misc.toInt(rollData.diffConditions));
|
||||
dialog.updateRollResult();
|
||||
}
|
||||
if (this.rollData.selectedSort) {
|
||||
this.setSelectedSort(this.rollData.selectedSort);
|
||||
this.html.find(".draconic").val(this.rollData.selectedSort.system.listIndex); // Uniquement a la selection du sort, pour permettre de changer
|
||||
}
|
||||
RdDItemSort.setCoutReveReel(this.rollData.selectedSort);
|
||||
this.html.find("[name='diffLibre']").val(Misc.toInt(this.rollData.diffLibre));
|
||||
this.html.find("[name='diffConditions']").val(Misc.toInt(this.rollData.diffConditions));
|
||||
this.updateRollResult(html);
|
||||
|
||||
this.html.find("[name='diffLibre']").change((event) => {
|
||||
// Setup everything onload
|
||||
$(function () { onLoad(); });
|
||||
|
||||
// Update !
|
||||
html.find('#diffLibre').change((event) => {
|
||||
this.rollData.diffLibre = Misc.toInt(event.currentTarget.value); // Update the selected bonus/malus
|
||||
this.updateRollResult(html);
|
||||
this.updateRollResult();
|
||||
});
|
||||
this.html.find("[name='diffConditions']").change((event) => {
|
||||
html.find('#diffConditions').change((event) => {
|
||||
this.rollData.diffConditions = Misc.toInt(event.currentTarget.value); // Update the selected bonus/malus
|
||||
this.updateRollResult(html);
|
||||
this.updateRollResult();
|
||||
});
|
||||
this.html.find("[name='force-dice-result']").change((event) => {
|
||||
html.find('#force-dice-result').change((event) => {
|
||||
this.rollData.forceDiceResult = Misc.toInt(event.currentTarget.value);
|
||||
});
|
||||
this.html.find("[name='carac']").change((event) => {
|
||||
html.find('#carac').change((event) => {
|
||||
let caracKey = event.currentTarget.value;
|
||||
this.rollData.selectedCarac = this.rollData.carac[caracKey]; // Update the selectedCarac
|
||||
this.updateRollResult(html);
|
||||
this.updateRollResult();
|
||||
});
|
||||
this.html.find('.roll-draconic').change((event) => {
|
||||
html.find('.roll-draconic').change((event) => {
|
||||
let draconicKey = Misc.toInt(event.currentTarget.value);
|
||||
this.rollData.competence = this.rollData.draconicList[draconicKey]; // Update the selectedCarac
|
||||
this.updateRollResult(html);
|
||||
this.updateRollResult();
|
||||
});
|
||||
this.html.find('.roll-sort').change((event) => {
|
||||
html.find('.roll-sort').change((event) => {
|
||||
let sortKey = Misc.toInt(event.currentTarget.value);
|
||||
this.setSelectedSort(this.rollData.sortList[sortKey]);
|
||||
this.updateRollResult(html);
|
||||
this.html.find("[name='diffLibre']").val(this.rollData.diffLibre);
|
||||
this.updateRollResult();
|
||||
$("#diffLibre").val(this.rollData.diffLibre);
|
||||
});
|
||||
this.html.find('.roll-carac-competence').change((event) => {
|
||||
const competence = event.currentTarget.value;
|
||||
this.rollData.competence = this.rollData.competences.find(it => it.name == competence);
|
||||
this.updateRollResult(html);
|
||||
});
|
||||
this.html.find('.roll-signedraconique').change((event) => {
|
||||
html.find('.roll-signedraconique').change((event) => {
|
||||
let sortKey = Misc.toInt(event.currentTarget.value);
|
||||
this.setSelectedSigneDraconique(this.rollData.signes[sortKey]);
|
||||
this.updateRollResult(html);
|
||||
this.updateRollResult();
|
||||
});
|
||||
this.html.find("[name='ptreve-variable']").change((event) => {
|
||||
html.find('#ptreve-variable').change((event) => {
|
||||
let ptreve = Misc.toInt(event.currentTarget.value);
|
||||
this.rollData.selectedSort.system.ptreve_reel = ptreve;
|
||||
this.rollData.selectedSort.data.ptreve_reel = ptreve;
|
||||
console.log("RdDRollSelectDialog - Cout reve", ptreve);
|
||||
this.updateRollResult(html);
|
||||
this.updateRollResult();
|
||||
});
|
||||
this.html.find("[name='coupsNonMortels']").change((event) => {
|
||||
html.find("[name='coupsNonMortels']").change((event) => {
|
||||
this.rollData.dmg.mortalite = event.currentTarget.checked ? "non-mortel" : "mortel";
|
||||
this.updateRollResult(html);
|
||||
this.updateRollResult();
|
||||
});
|
||||
this.html.find('.cuisine-proportions').change((event) => {
|
||||
html.find('.cuisine-proportions').change((event) => {
|
||||
this.rollData.proportions = Number(event.currentTarget.value);
|
||||
this.updateRollResult(html);
|
||||
this.updateRollResult();
|
||||
});
|
||||
this.html.find('.select-by-name').change((event) => {
|
||||
html.find('.select-by-name').change((event) => {
|
||||
const attribute = event.currentTarget.attributes['name'].value;
|
||||
this.rollData[attribute] = event.currentTarget.value;
|
||||
this.updateRollResult(html);
|
||||
this.updateRollResult();
|
||||
});
|
||||
this.html.find('.checkbox-by-name').change((event) => {
|
||||
html.find('.checkbox-by-name').change((event) => {
|
||||
const attribute = event.currentTarget.attributes['name'].value;
|
||||
this.rollData[attribute] = event.currentTarget.checked;
|
||||
this.updateRollResult(html);
|
||||
this.updateRollResult();
|
||||
});
|
||||
this.html.find('input.use-encTotal').change((event) => {
|
||||
this.rollData.use.encTotal = event.currentTarget.checked;
|
||||
this.updateRollResult(html);
|
||||
});
|
||||
this.html.find('input.use-surenc').change((event) => {
|
||||
this.rollData.use.surenc = event.currentTarget.checked;
|
||||
this.updateRollResult(html);
|
||||
});
|
||||
this.html.find('.appel-moral').click((event) => { /* l'appel au moral, qui donne un bonus de +1 */
|
||||
this.rollData.use.moral = !this.rollData.use.moral;
|
||||
const appelMoral = this.html.find('.icon-appel-moral')[0];
|
||||
const tooltip = this.html.find('.tooltipAppelAuMoralText')[0];
|
||||
if (this.rollData.use.moral) {
|
||||
html.find('.appel-moral').click((event) => { /* l'appel au moral, qui donne un bonus de +1 */
|
||||
this.rollData.useMoral = !this.rollData.useMoral;
|
||||
const appelMoral = html.find('.icon-appel-moral')[0];
|
||||
const tooltip = html.find('.tooltipAppelAuMoralText')[0];
|
||||
if (this.rollData.useMoral) {
|
||||
if (this.rollData.moral > 0) {
|
||||
tooltip.innerHTML = "Appel au moral";
|
||||
appelMoral.src = "/systems/foundryvtt-reve-de-dragon/icons/moral-heureux.svg";
|
||||
@ -229,68 +259,47 @@ export class RdDRoll extends Dialog {
|
||||
tooltip.innerHTML = "Sans appel au moral";
|
||||
appelMoral.src = "/systems/foundryvtt-reve-de-dragon/icons/moral-neutre.svg";
|
||||
}
|
||||
this.updateRollResult(html);
|
||||
this.updateRollResult();
|
||||
});
|
||||
// Section Méditation
|
||||
this.html.find('.conditionMeditation').change((event) => {
|
||||
let condition = event.currentTarget.attributes['name'].value;
|
||||
html.find('.conditionMeditation').change((event) => {
|
||||
let condition = event.currentTarget.attributes['id'].value;
|
||||
this.rollData.conditionMeditation[condition] = event.currentTarget.checked;
|
||||
this.updateRollResult(html);
|
||||
this.updateRollResult();
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
close() {
|
||||
if (this.rollData.canClose) {
|
||||
return super.close();
|
||||
}
|
||||
ui.notifications.info("Vous devez faire ce jet de dés!");
|
||||
}
|
||||
|
||||
async onAction(action) {
|
||||
this.rollData.forceDiceResult = Number.parseInt(this.html.find("[name='force-dice-result']").val()) ?? -1;
|
||||
await RdDResolutionTable.rollData(this.rollData);
|
||||
console.log("RdDRoll -=>", this.rollData, this.rollData.rolled);
|
||||
if (action.callbacks)
|
||||
for (let callback of action.callbacks) {
|
||||
if (callback.condition == undefined || callback.condition(this.rollData)) {
|
||||
await callback.action(this.rollData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async setSelectedSort(sort) {
|
||||
this.rollData.selectedSort = sort; // Update the selectedCarac
|
||||
this.rollData.competence = RdDItemCompetence.getVoieDraconic(this.rollData.draconicList, sort.system.draconic);
|
||||
this.rollData.competence = RdDItemCompetence.getVoieDraconic(this.rollData.draconicList, sort.data.draconic);
|
||||
this.rollData.bonus = RdDItemSort.getCaseBonus(sort, this.rollData.tmr.coord);
|
||||
this.rollData.diffLibre = RdDItemSort.getDifficulte(sort, -7);
|
||||
RdDItemSort.setCoutReveReel(sort);
|
||||
const htmlSortDescription = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/partial-description-sort.html", { sort: sort });
|
||||
this.html.find(".sort-ou-rituel").text(sort.system.isrituel ? "rituel" : "sort");
|
||||
this.html.find(".bonus-case").text(`${this.rollData.bonus}%`);
|
||||
this.html.find(".placeholder-description-sort").children().remove();
|
||||
this.html.find(".placeholder-description-sort").append(htmlSortDescription);
|
||||
this.html.find(".roll-draconic").val(sort.system.listIndex);
|
||||
this.html.find(".div-sort-difficulte-fixe").text(Misc.toSignedString(sort.system.difficulte));
|
||||
this.html.find(".div-sort-ptreve-fixe").text(sort.system.ptreve);
|
||||
$(".sort-ou-rituel").text(sort.data.isrituel ? "rituel" : "sort");
|
||||
$(".bonus-case").text(`${this.rollData.bonus}%`);
|
||||
$(".details-sort").remove();
|
||||
$(".description-sort").append(htmlSortDescription);
|
||||
$(".roll-draconic").val(sort.data.listIndex);
|
||||
$(".div-sort-difficulte-fixe").text(Misc.toSignedString(sort.data.difficulte));
|
||||
$(".div-sort-ptreve-fixe").text(sort.data.ptreve);
|
||||
const diffVariable = RdDItemSort.isDifficulteVariable(sort);
|
||||
const coutVariable = RdDItemSort.isCoutVariable(sort);
|
||||
|
||||
HtmlUtility._showControlWhen(this.html.find(".div-sort-non-rituel"), !sort.system.isrituel);
|
||||
HtmlUtility._showControlWhen(this.html.find(".div-sort-difficulte-var"), diffVariable);
|
||||
HtmlUtility._showControlWhen(this.html.find(".div-sort-difficulte-fixe"), !diffVariable);
|
||||
HtmlUtility._showControlWhen(this.html.find(".div-sort-ptreve-var"), coutVariable);
|
||||
HtmlUtility._showControlWhen(this.html.find(".div-sort-ptreve-fixe"), !coutVariable);
|
||||
HtmlUtility._showControlWhen($(".div-sort-non-rituel"), !sort.data.isrituel);
|
||||
HtmlUtility._showControlWhen($(".div-sort-difficulte-var"), diffVariable);
|
||||
HtmlUtility._showControlWhen($(".div-sort-difficulte-fixe"), !diffVariable);
|
||||
HtmlUtility._showControlWhen($(".div-sort-ptreve-var"), coutVariable);
|
||||
HtmlUtility._showControlWhen($(".div-sort-ptreve-fixe"), !coutVariable);
|
||||
}
|
||||
|
||||
async setSelectedSigneDraconique(signe) {
|
||||
async setSelectedSigneDraconique(signe){
|
||||
this.rollData.signe = signe;
|
||||
this.rollData.diffLibre = signe.system.difficulte,
|
||||
$(".signe-difficulte").text(Misc.toSignedString(this.rollData.diffLibre));
|
||||
this.rollData.diffLibre = Misc.data(signe).data.difficulte,
|
||||
$(".signe-difficulte").text(Misc.toSignedString(this.rollData.diffLibre));
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async updateRollResult(html) {
|
||||
async updateRollResult() {
|
||||
let rollData = this.rollData;
|
||||
|
||||
rollData.dmg = rollData.attackerRoll?.dmg ?? RdDBonus.dmg(rollData, this.actor.getBonusDegat())
|
||||
@ -300,35 +309,36 @@ export class RdDRoll extends Dialog {
|
||||
rollData.use.appelAuMoral = this.actor.isPersonnage() && RdDCarac.isActionPhysique(rollData.selectedCarac);
|
||||
let dmgText = Misc.toSignedString(rollData.dmg.total);
|
||||
|
||||
switch (rollData.mortalite) {
|
||||
case 'non-mortel': dmgText = `(${dmgText}) non-mortel`; break;
|
||||
case 'empoignade': dmgText = `empoignade`; break;
|
||||
switch (rollData.mortalite){
|
||||
case 'non-mortel': dmgText = `(${dmgText}) non-mortel`; break;
|
||||
case 'empoignade': dmgText = `empoignade`; break;
|
||||
}
|
||||
|
||||
RollDataAjustements.calcul(rollData, this.actor);
|
||||
rollData.finalLevel = this._computeFinalLevel(rollData);
|
||||
|
||||
const resolutionTable = await RdDResolutionTable.buildHTMLTable(RdDResolutionTable.subTable(rollData.caracValue, rollData.finalLevel))
|
||||
const adjustements = await this.buildAjustements(rollData);
|
||||
|
||||
HtmlUtility._showControlWhen(this.html.find(".use-encTotal"), rollData.ajustements.encTotal.visible && RdDCarac.isAgiliteOuDerivee(rollData.selectedCarac));
|
||||
HtmlUtility._showControlWhen(this.html.find(".use-surenc"), rollData.ajustements.surenc.visible && RdDCarac.isActionPhysique(rollData.selectedCarac));
|
||||
HtmlUtility._showControlWhen(this.html.find(".utilisation-moral"), rollData.use.appelAuMoral);
|
||||
HtmlUtility._showControlWhen(this.html.find(".diffMoral"), rollData.ajustements.moralTotal.used);
|
||||
HtmlUtility._showControlWhen(this.html.find(".divAppelAuMoral"), rollData.use.appelAuMoral);
|
||||
HtmlUtility._showControlWhen($(".diffMoral"), rollData.ajustements.moralTotal.used);
|
||||
HtmlUtility._showControlWhen($(".divAppelAuMoral"), rollData.use.appelAuMoral);
|
||||
HtmlUtility._showControlWhen($("#etat-general"), !RdDCarac.isIgnoreEtatGeneral(rollData));
|
||||
HtmlUtility._showControlWhen($("#ajust-astrologique"), RdDResolutionTable.isAjustementAstrologique(rollData));
|
||||
|
||||
// Mise à jour valeurs
|
||||
this.html.find(".dialog-roll-title").text(this._getTitle(rollData));
|
||||
this.html.find("[name='coupsNonMortels']").prop('checked', rollData.mortalite == 'non-mortel');
|
||||
this.html.find(".dmg-arme-actor").text(dmgText);
|
||||
this.html.find("div.placeholder-ajustements").empty().append(adjustements);
|
||||
this.html.find("div.placeholder-resolution").empty().append(resolutionTable)
|
||||
$(".dialog-roll-title").text(this._getTitle(rollData));
|
||||
$("[name='coupsNonMortels']").prop('checked', rollData.mortalite == 'non-mortel');
|
||||
$(".dmg-arme-actor").text(dmgText);
|
||||
$('.table-ajustement').remove();
|
||||
$(".table-resolution").remove();
|
||||
$(".table-proba-reussite").remove();
|
||||
$("#tableAjustements").append(await this.buildAjustements(rollData));
|
||||
$("#tableResolution").append(RdDResolutionTable.buildHTMLTableExtract(rollData.caracValue, rollData.finalLevel));
|
||||
$("#tableProbaReussite").append(RdDResolutionTable.buildHTMLResults(rollData.caracValue, rollData.finalLevel));
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async buildAjustements(rollData) {
|
||||
return await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/partial-roll-ajustements.html`, rollData);
|
||||
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/partial-roll-ajustements.html`, rollData);
|
||||
return html;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -338,19 +348,31 @@ export class RdDRoll extends Dialog {
|
||||
/* -------------------------------------------- */
|
||||
_computeDiffCompetence(rollData) {
|
||||
if (rollData.competence) {
|
||||
return Misc.toInt(rollData.competence.system.niveau);
|
||||
return Misc.toInt(rollData.competence.data.niveau);
|
||||
}
|
||||
if (rollData.draconicList) {
|
||||
return Misc.toInt(rollData.competence.system.niveau);
|
||||
return Misc.toInt(rollData.competence.data.niveau);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_computeDiffLibre(rollData) {
|
||||
let diffLibre = Misc.toInt(rollData.diffLibre);
|
||||
if (rollData.draconicList && rollData.selectedSort) {
|
||||
return RdDItemSort.getDifficulte(rollData.selectedSort, diffLibre);
|
||||
}
|
||||
return diffLibre;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_computeMalusArmure(rollData) {
|
||||
let malusArmureValue = 0;
|
||||
if (rollData.malusArmureValue && (rollData.selectedCarac.label == "Agilité" || rollData.selectedCarac.label == "Dérobée")) {
|
||||
$("#addon-message").text("Malus armure appliqué : " + rollData.malusArmureValue);
|
||||
malusArmureValue = rollData.malusArmureValue;
|
||||
} else {
|
||||
$("#addon-message").text("");
|
||||
}
|
||||
return malusArmureValue;
|
||||
}
|
||||
@ -366,7 +388,7 @@ export class RdDRoll extends Dialog {
|
||||
return compName + " - " + rollData.selectedSort.name;
|
||||
}
|
||||
// If a weapon is there, add it in the title
|
||||
const niveau = Misc.toSignedString(rollData.competence.system.niveau)
|
||||
const niveau = Misc.toSignedString(rollData.competence.data.niveau);
|
||||
if (compName == carac) {
|
||||
// cas des créatures
|
||||
return carac + " Niveau " + niveau
|
||||
|
@ -1,110 +1,86 @@
|
||||
import { Grammar } from "./grammar.js";
|
||||
import { CompendiumTable, CompendiumTableHelpers, SystemCompendiums } from "./settings/system-compendiums.js";
|
||||
|
||||
export class RdDRollTables {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async genericGetTableResult(tableName, toChat) {
|
||||
let table = RdDRollTables.getWorldTable(tableName) ?? (await RdDRollTables.getSystemTable(tableName));
|
||||
const draw = await table.draw({ displayChat: toChat, rollMode: "gmroll" });
|
||||
let table = game.tables.find(table => table.name.toLowerCase() == tableName.toLowerCase())
|
||||
if ( !table) {
|
||||
const pack = game.packs.get("foundryvtt-reve-de-dragon.tables-diverses");
|
||||
const index = await pack.getIndex();
|
||||
const entry = index.find(e => e.name === tableName);
|
||||
table = await pack.getDocument(entry._id);
|
||||
}
|
||||
const draw = await table.draw({ displayChat: toChat, rollMode: "gmroll"});
|
||||
console.log("RdDRollTables", tableName, toChat, ":", draw);
|
||||
return draw.results.length > 0 ? draw.results[0] : undefined;
|
||||
}
|
||||
|
||||
static getWorldTable(tableName) {
|
||||
return game.tables.find(table => table.name.toLowerCase() == tableName.toLowerCase());
|
||||
}
|
||||
|
||||
static async getSystemTable(tableName) {
|
||||
const pack = SystemCompendiums.getPack("tables-diverses");
|
||||
const index = await pack.getIndex();
|
||||
const entry = index.find(e => e.name === tableName);
|
||||
return await pack.getDocument(entry._id);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async drawItemFromRollTable(tableName, toChat = false) {
|
||||
const drawResult = await RdDRollTables.genericGetTableResult(tableName, toChat);
|
||||
const pack = game.packs.get(drawResult.documentCollection)
|
||||
return await pack.getDocument(drawResult.documentId)
|
||||
const pack = game.packs.get(drawResult.data.collection);
|
||||
return await pack.getDocument(drawResult.data.resultId);
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async drawTextFromRollTable(tableName, toChat) {
|
||||
const drawResult = await RdDRollTables.genericGetTableResult(tableName, toChat);
|
||||
return drawResult.text;
|
||||
return drawResult.data.text;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async getCompetence(toChat = false) {
|
||||
if (toChat == 'liste') {
|
||||
return await RdDRollTables.listOrRoll('competences', 'Item', ['competence'], toChat, it => 1);
|
||||
}
|
||||
else {
|
||||
return await RdDRollTables.drawItemFromRollTable("Détermination aléatoire de compétence", toChat);
|
||||
}
|
||||
return await RdDRollTables.drawItemFromRollTable("Détermination aléatoire de compétence", toChat);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async getSouffle(toChat = false) {
|
||||
return await RdDRollTables.listOrRoll('souffles-de-dragon', 'Item', ['souffle'], toChat);
|
||||
return await RdDRollTables.drawItemFromRollTable("Souffles de Dragon", toChat);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async getQueue(toChat = false) {
|
||||
return await RdDRollTables.listOrRoll('queues-de-dragon', 'Item', ['queue'], toChat);
|
||||
let queue = await RdDRollTables.drawItemFromRollTable("Queues de dragon", toChat);
|
||||
if (queue.name.toLowerCase().includes('lancinant') ) {
|
||||
return await RdDRollTables.getDesirLancinant(toChat);
|
||||
}
|
||||
if (queue.name.toLowerCase().includes('fixe') ) {
|
||||
return await RdDRollTables.getIdeeFixe(toChat);
|
||||
}
|
||||
return queue;
|
||||
}
|
||||
|
||||
static async getDesirLancinant(toChat = false) {
|
||||
return await RdDRollTables.listOrRoll('queues-de-dragon', 'Item', ['queue'], toChat,
|
||||
it => it.system.frequence,
|
||||
it => it.system.categorie == 'lancinant');
|
||||
return await RdDRollTables.drawItemFromRollTable("Désirs lancinants", toChat);
|
||||
}
|
||||
|
||||
|
||||
static async getIdeeFixe(toChat = false) {
|
||||
return await RdDRollTables.listOrRoll('queues-de-dragon', 'Item', ['queue'], toChat,
|
||||
it => it.system.frequence,
|
||||
it => it.system.categorie == 'ideefixe');
|
||||
return await RdDRollTables.drawItemFromRollTable("Idées fixes", toChat);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async getTeteHR(toChat = false) {
|
||||
return await RdDRollTables.listOrRoll('tetes-de-dragon-pour-haut-revants', 'Item', ['tete'], toChat);
|
||||
return await RdDRollTables.drawItemFromRollTable("Têtes de Dragon pour haut-rêvants", toChat);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async getTete(toChat = false) {
|
||||
return await RdDRollTables.listOrRoll('tetes-de-dragon-pour-tous-personnages', 'Item', ['tete'], toChat);
|
||||
return await RdDRollTables.drawItemFromRollTable("Têtes de Dragon pour tous personnages", toChat);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async getOmbre(toChat = false) {
|
||||
return await RdDRollTables.listOrRoll('ombres-de-thanatos', 'Item', ['ombre'], toChat);
|
||||
return await RdDRollTables.drawItemFromRollTable("Ombre de Thanatos", toChat);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async getTarot(toChat = true) {
|
||||
return await RdDRollTables.listOrRoll('tarot-draconique', 'Item', ['tarot'], toChat);
|
||||
return await RdDRollTables.drawItemFromRollTable("Tarot Draconique", toChat);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async listOrRoll(compendium, type, subTypes, toChat, itemFrequence = it => it.system.frequence, filter = it => true) {
|
||||
const table = new CompendiumTable(compendium, type, subTypes);
|
||||
if (toChat == 'liste') {
|
||||
return await table.toChatMessage(itemFrequence, filter);
|
||||
}
|
||||
const row = await table.getRandom(itemFrequence, filter);
|
||||
if (row) {
|
||||
await CompendiumTableHelpers.tableRowToChatMessage(row, type);
|
||||
return row.document;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async getMaladresse(options = { toChat: false, arme: false }) {
|
||||
static async getMaladresse(options = {toChat: false, arme: false}) {
|
||||
return await RdDRollTables.drawTextFromRollTable(
|
||||
options.arme ? "Maladresse armé" : "Maladresses non armé",
|
||||
options.toChat);
|
||||
}
|
||||
|
||||
}
|
||||
|