- Etant donné son ${arme.name}, son initative pour ce premier round est désormais de ${initData.init}.
+ Etant donné son ${arme.name}, son initiative pour ce premier round est désormais de ${initData.init}.
`
ChatMessage.create({ content: msg });
game.combat.setInitiative(combatant._id, initData.init);
@@ -725,7 +726,7 @@ export class RdDCombat {
/* -------------------------------------------- */
async _onAttaqueParticuliere(rollData) {
RdDCombat._storeAttaque(this.attackerId, rollData);
- this.attacker.decItemUse( rollData.arme._id ); // Usage décrémenté sur particulière
+ this.attacker.decItemUse(rollData.arme._id); // Usage décrémenté sur particulière
// Finesse et Rapidité seulement en mêlée et si la difficulté libre est de -1 minimum
const isMeleeDiffNegative = rollData.selectedCarac.label == "Mêlée" && rollData.diffLibre < 0;
@@ -733,7 +734,7 @@ export class RdDCombat {
alias: this.attacker.name,
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.attacker.name),
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-particuliere.html', {
- alias: this.attacker.name,
+ actor: this.attacker,
attackerId: this.attackerId,
defenderTokenId: this.defenderTokenId,
isFinesse: isMeleeDiffNegative,
@@ -1109,7 +1110,7 @@ export class RdDCombat {
resistance -= perteResistance;
defenderRoll.show.deteriorationArme = resistance <= 0 ? 'brise' : 'perte';
defenderRoll.show.perteResistance = perteResistance;
- this.defender.updateEmbeddedEntity("OwnedItem", { _id: defenderRoll.arme._id, 'data.resistance': resistance });
+ this.defender.updateEmbeddedDocuments('Item', [{ _id: defenderRoll.arme._id, 'data.resistance': resistance }]);
}
}
} else {
@@ -1126,7 +1127,7 @@ export class RdDCombat {
resistance -= dmg;
defenderRoll.show.deteriorationArme = resistance <= 0 ? 'brise' : 'perte';
defenderRoll.show.perteResistance = dmg;
- this.defender.updateEmbeddedEntity("OwnedItem", { _id: defenderRoll.arme._id, 'data.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)
@@ -1248,7 +1249,7 @@ export class RdDCombat {
static async displayActorCombatStatus(combat, actor) {
let data = {
combatId: combat._id,
- alias: actor.name,
+ actor: actor,
etatGeneral: actor.getEtatGeneral(),
isSonne: actor.getSonne(),
blessuresStatus: actor.computeResumeBlessure(),
diff --git a/module/rdd-commands.js b/module/rdd-commands.js
index b085c758..8a091058 100644
--- a/module/rdd-commands.js
+++ b/module/rdd-commands.js
@@ -23,6 +23,8 @@ export class 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" });
@@ -255,7 +257,7 @@ export class RdDCommands {
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]);
- 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.computeDeltaXP(from, to)}`);
}
else {
return false;
diff --git a/module/rdd-compendium-organiser.js b/module/rdd-compendium-organiser.js
index ad7e1ea2..0901d8bb 100644
--- a/module/rdd-compendium-organiser.js
+++ b/module/rdd-compendium-organiser.js
@@ -36,15 +36,15 @@ export class RddCompendiumOrganiser {
Hooks.on('renderCompendium', async (pack, html, data) => RddCompendiumOrganiser.onRenderCompendium(pack, html, data))
}
- static async onRenderCompendium(pack, html, data) {
- console.log('onRenderCompendium', pack, html, data);
+ static async onRenderCompendium(compendium, html, data) {
+ console.log('onRenderCompendium', compendium, html, data);
+ let pack = compendium.collection
if (pack.metadata.system === 'foundryvtt-reve-de-dragon') {
const content = await pack.getContent();
-
+
html.find('.directory-item').each((i, element) => {
- let entity = content.find(it => it._id === element.dataset.entryId);
-
- if (entity?.entity === 'Actor' || entity?.entity === 'Item') {
+ let entity = pack.get(element.dataset.documentId);
+ if (entity?.entity === 'Item') {
const typeName = typeDisplayName[entity.data.type] ?? Misc.upperFirst(entity.data.type);
RddCompendiumOrganiser.insertEntityType(element, typeName);
}
diff --git a/module/rdd-hotbar-drop.js b/module/rdd-hotbar-drop.js
index 12b925bb..0725f0a0 100644
--- a/module/rdd-hotbar-drop.js
+++ b/module/rdd-hotbar-drop.js
@@ -11,11 +11,11 @@ export class RdDHotbar {
Hooks.on("hotbarDrop", async (bar, data, slot) => {
// Create item macro if rollable item - weapon, spell, prayer, trait, or skill
- if (data.type == "Item") {
+ if (data.type == 'Item') {
if (data.data.type != "arme" && data.data.type != "competence" )
return
let item = data.data
- let command = `game.system.rdd.RdDHotbar.rollMacro("${item.name}", "${item.type}");`;
+ let command = `game.system.rdd.RdDHotbar.rollMacro("${item.name}", "${item.data.type}");`;
let macro = game.macros.entities.find(m => (m.name === item.name) && (m.command === command));
if (!macro) {
macro = await Macro.create({
@@ -70,10 +70,10 @@ export class RdDHotbar {
let item = actor ? actor.items.find(i => i.name === itemName && i.type == itemType) : null;
if (!item) return ui.notifications.warn(`Impossible de trouver l'objet de cette macro`);
- item = item.data;
+ item = item.data.data;
// Trigger the item roll
- switch (item.type) {
+ switch (item.data.type) {
case "arme":
return actor.rollArme(item.data.competence, itemName);
case "competence":
diff --git a/module/rdd-main.js b/module/rdd-main.js
index 2b7d2e43..1c45db7a 100644
--- a/module/rdd-main.js
+++ b/module/rdd-main.js
@@ -133,7 +133,8 @@ Hooks.once("init", async function () {
/* -------------------------------------------- */
// Define custom Entity classes
- CONFIG.Actor.entityClass = RdDActor;
+ CONFIG.Actor.documentClass = RdDActor;
+ //CONFIG.Actor.entityClass = RdDActor;
CONFIG.RDD = {
resolutionTable: RdDResolutionTable.resolutionTable,
carac_array: RdDUtility.getCaracArray(),
@@ -150,7 +151,8 @@ Hooks.once("init", async function () {
Actors.registerSheet("foundryvtt-reve-de-dragon", RdDActorEntiteSheet, { types: ["entite"], makeDefault: true });
Items.unregisterSheet("core", ItemSheet);
Items.registerSheet("foundryvtt-reve-de-dragon", RdDItemSheet, { makeDefault: true });
- CONFIG.Combat.entityClass = RdDCombatManager;
+ //CONFIG.Combat.entityClass = RdDCombatManager;
+ CONFIG.Combat.documentClass = RdDCombatManager;
// préparation des différents modules
RdDCommands.init();
@@ -171,7 +173,7 @@ function messageDeBienvenue() {
if (game.user.isGM) {
ChatUtility.removeChatMessageContaining('');
ChatMessage.create({
- user: game.user._id,
+ user: game.user.data._id,
content: `
Bienvenue dans le Rêve des Dragons !
Vous trouverez quelques informations pour démarrer dans ce document : @Compendium[foundryvtt-reve-de-dragon.rappel-des-regles.7uGrUHGdPu0EmIu2]{Documentation MJ/Joueurs}
La commande /aide
dans le chat permet de voir les commandes spécifiques à Rêve de Dragon.
diff --git a/module/rdd-roll.js b/module/rdd-roll.js
index 079fc277..a50b5a53 100644
--- a/module/rdd-roll.js
+++ b/module/rdd-roll.js
@@ -39,7 +39,7 @@ export class RdDRoll extends Dialog {
/* -------------------------------------------- */
static _setDefaultOptions(actor, rollData) {
let defaultRollData = {
- alias: actor.name,
+ actor: actor,
ajustementsConditions: CONFIG.RDD.ajustementsConditions,
difficultesLibres: CONFIG.RDD.difficultesLibres,
etat: actor.getEtatGeneral(),
diff --git a/module/rdd-rolltables.js b/module/rdd-rolltables.js
index 957c130a..74d06152 100644
--- a/module/rdd-rolltables.js
+++ b/module/rdd-rolltables.js
@@ -48,14 +48,22 @@ export class RdDRollTables {
static async getQueue(toChat = false) {
let queue = await RdDRollTables.drawItemFromRollTable("Queues de dragon", toChat);
if (queue.name.toLowerCase().includes('lancinant') ) {
- queue = await RdDRollTables.drawItemFromRollTable("Désirs lancinants", toChat);
+ return await RdDRollTables.getDesirLancinant(toChat);
}
if (queue.name.toLowerCase().includes('fixe') ) {
- queue = await RdDRollTables.drawItemFromRollTable("Idées fixes", toChat);
+ return await RdDRollTables.getIdeeFixe(toChat);
}
return queue;
}
+ static async getDesirLancinant(toChat = false) {
+ return await RdDRollTables.drawItemFromRollTable("Désirs lancinants", toChat);
+ }
+
+ static async getIdeeFixe(toChat = false) {
+ return await RdDRollTables.drawItemFromRollTable("Idées fixes", toChat);
+ }
+
/* -------------------------------------------- */
static async getTeteHR(toChat = false) {
return await RdDRollTables.drawItemFromRollTable("Têtes de Dragon pour haut-rêvants", toChat);
diff --git a/module/rdd-tmr-dialog.js b/module/rdd-tmr-dialog.js
index a3bcff7e..6f67b0b7 100644
--- a/module/rdd-tmr-dialog.js
+++ b/module/rdd-tmr-dialog.js
@@ -76,7 +76,7 @@ export class RdDTMRDialog extends Dialog {
}
loadRencontres() {
- this.rencontresExistantes = duplicate(this.actor.getTMRRencontres()).list;
+ this.rencontresExistantes = duplicate(this.actor.getTMRRencontres());
}
/* -------------------------------------------- */
@@ -108,6 +108,11 @@ export class RdDTMRDialog extends Dialog {
this._createTokens();
}
+ removeToken(tmr, casetmr) {
+ this._removeTokens(t => t.coordTMR() == tmr.coord && t.caseSpeciale?._id == casetmr._id);
+ this.updateTokens()
+ }
+
/* -------------------------------------------- */
_getTokensCasesTmr() {
return this.casesSpeciales.map(c => this._tokenCaseSpeciale(c)).filter(token => token);
@@ -142,7 +147,7 @@ export class RdDTMRDialog extends Dialog {
async activateListeners(html) {
super.activateListeners(html);
- document.getElementById("tmrrow1").insertCell(1).append(this.pixiApp.view);
+ document.getElementById("tmrrow1").insertCell(0).append(this.pixiApp.view);
if (this.viewOnly) {
html.find('#lancer-sort').remove();
@@ -168,7 +173,6 @@ export class RdDTMRDialog extends Dialog {
let tmr = TMRUtility.getTMR(this.actor.data.data.reve.tmrpos.coord);
await this.manageRencontre(tmr, () => {
this.postRencontre(tmr);
- this.actor.displayTMRQueueSouffleInformation();
});
}
@@ -176,7 +180,7 @@ export class RdDTMRDialog extends Dialog {
updateValuesDisplay() {
let ptsreve = document.getElementById("tmr-pointsreve-value");
ptsreve.innerHTML = this.actor.data.data.reve.reve.value;
-
+ console.log( this.actor.data.data );
let tmrpos = document.getElementById("tmr-pos");
let tmr = TMRUtility.getTMR(this.actor.data.data.reve.tmrpos.coord);
tmrpos.innerHTML = this.actor.data.data.reve.tmrpos.coord + " (" + tmr.label + ")";
@@ -300,7 +304,6 @@ export class RdDTMRDialog extends Dialog {
let rencontreData = {
actor: this.actor,
- alias: this.actor.name,
reveDepart: this.actor.getReveActuel(),
competence: this.actor.getBestDraconic(),
rencontre: this.currentRencontre,
@@ -427,7 +430,6 @@ export class RdDTMRDialog extends Dialog {
// simuler une rencontre
let rencontreData = {
actor: this.actor,
- alias: this.actor.name,
reveDepart: this.actor.getReveActuel(),
competence: this.actor.getBestDraconic(),
rencontre: this.currentRencontre,
@@ -498,9 +500,7 @@ export class RdDTMRDialog extends Dialog {
}
async _resultatMaitriseCaseHumide(rollData) {
- if (rollData.rolled.isETotal) {
- rollData.souffle = await this.actor.ajouterSouffle({ chat: false });
- }
+ await this.souffleSiEchecTotal(rollData);
this.toclose = rollData.rolled.isEchec;
if (rollData.rolled.isSuccess && rollData.double) {
rollData.previous = { rolled: rollData.rolled, ajustements: rollData.ajustements };
@@ -518,6 +518,12 @@ export class RdDTMRDialog extends Dialog {
}
}
+ async souffleSiEchecTotal(rollData) {
+ if (rollData.rolled.isETotal) {
+ rollData.souffle = await this.actor.ajouterSouffle({ chat: false });
+ }
+ }
+
/* -------------------------------------------- */
isCaseHumide(tmr) {
if (!(TMRUtility.isCaseHumide(tmr) || this.isCaseHumideAdditionelle(tmr))) {
@@ -558,16 +564,29 @@ export class RdDTMRDialog extends Dialog {
await this._conquerir(tmr, {
difficulte: -9,
action: 'Conquérir la cité',
- onConqueteReussie: r => EffetsDraconiques.fermetureCites.onConquete(r.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr)),
- onConqueteEchec: r => this.close(),
+ onConqueteReussie: r => EffetsDraconiques.fermetureCites.onVisiteSupprimer(r.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr)),
+ onConqueteEchec: r => {
+ this.souffleSiEchecTotal(rollData);
+ this.close()
+ },
canClose: false
});
}
}
-
- removeToken(tmr, casetmr) {
- this._removeTokens(t => t.coordTMR() == tmr.coord && t.caseSpeciale?._id == casetmr._id);
- this.updateTokens()
+ /* -------------------------------------------- */
+ async purifierPeriple(tmr) {
+ if (EffetsDraconiques.periple.find(this.casesSpeciales, tmr.coord)) {
+ await this._conquerir(tmr, {
+ difficulte: EffetsDraconiques.periple.getDifficulte(tmr),
+ action: 'Purifier ' + TMRUtility.getTMRDescr(tmr.coord),
+ onConqueteReussie: r => EffetsDraconiques.periple.onVisiteSupprimer(r.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr)),
+ onConqueteEchec: r => {
+ this.souffleSiEchecTotal(rollData);
+ this.close()
+ },
+ canClose: false
+ });
+ }
}
/* -------------------------------------------- */
@@ -576,8 +595,8 @@ export class RdDTMRDialog extends Dialog {
await this._conquerir(tmr, {
difficulte: -7,
action: 'Conquérir',
- onConqueteReussie: r => EffetsDraconiques.conquete.onConquete(r.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr)),
- onConqueteEchec: r => { },
+ onConqueteReussie: r => EffetsDraconiques.conquete.onVisiteSupprimer(r.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr)),
+ onConqueteEchec: r => this.close(),
canClose: false
});
}
@@ -639,8 +658,9 @@ export class RdDTMRDialog extends Dialog {
dialog.render(true);
}
- async validerPelerinage(tmr) {
- await EffetsDraconiques.pelerinage.onFinPelerinage(this.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr));
+ async validerVisite(tmr) {
+ await EffetsDraconiques.pelerinage.onVisiteSupprimer(this.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr));
+ await EffetsDraconiques.urgenceDraconique.onVisiteSupprimer(this.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr));
}
@@ -649,11 +669,12 @@ export class RdDTMRDialog extends Dialog {
let sortReserveList = TMRUtility.getSortReserveList(this.sortsReserves, coord);
if (sortReserveList.length > 0) {
- if (EffetsDraconiques.isSortImpossible(this.actor)) {
+ if (EffetsDraconiques.isSortReserveImpossible(this.actor)) {
ui.notifications.error("Une queue ou un souffle vous empèche de déclencher de sort!");
return;
}
- if (EffetsDraconiques.isReserveEnSecurite(this.actor) || this.isReserveExtensible(coord)) {
+ if (!EffetsDraconiques.isUrgenceDraconique(this.actor) &&
+ (EffetsDraconiques.isReserveEnSecurite(this.actor) || this.isReserveExtensible(coord))) {
let msg = "Vous êtes sur une case avec un Sort en Réserve. Grâce à votre Tête
Reserve en Sécurité ou
Réserve Exensible, vous pouvez contrôler le déclenchement. Cliquez si vous souhaitez le déclencher :
";
for (let sortReserve of sortReserveList) {
msg += "- " + sortReserve.sort.name + "
";
@@ -663,9 +684,9 @@ export class RdDTMRDialog extends Dialog {
content: msg,
whisper: ChatMessage.getWhisperRecipients(game.user.name)
});
- } else {
- await this.processSortReserve(sortReserveList[0]);
+ return;
}
+ await this.processSortReserve(sortReserveList[0]);
}
}
@@ -835,18 +856,19 @@ export class RdDTMRDialog extends Dialog {
if (!(this.viewOnly || this.currentRencontre)) {
await this.manageCaseHumide(tmr);
await this.conquerirCiteFermee(tmr);
+ await this.purifierPeriple(tmr);
await this.conquerirTMR(tmr);
- await this.validerPelerinage(tmr);
+ await this.validerVisite(tmr);
await this.declencheSortEnReserve(tmr.coord);
await this.actor.checkSoufflePeage(tmr);
}
}
-
+
/* -------------------------------------------- */
async forceDemiRevePositionView() {
this._updateDemiReve();
}
-
+
/* -------------------------------------------- */
async forceDemiRevePosition(coord) {
await this.actor.updateCoordTMR(coord);
diff --git a/module/rdd-utility.js b/module/rdd-utility.js
index 482b829d..208ea44c 100644
--- a/module/rdd-utility.js
+++ b/module/rdd-utility.js
@@ -12,14 +12,14 @@ import { Grammar } from "./grammar.js";
/* -------------------------------------------- */
const categorieCompetences = {
- "generale": { level: "-4", label: "Générales" },
- "particuliere": { level: "-8", label: "Particulières" },
- "specialisee": { level: "-11", label: "Spécialisées" },
- "connaissance": { level: "-11", label: "Connaissances" },
- "draconic": { level: "-11", label: "Draconics" },
- "melee": { level: "-6", label: "Mêlée" },
- "tir": { level: "-8", label: "Tir" },
- "lancer": { level: "-8", label: "Lancer" }
+ "generale": { level: -4, label: "Générales" },
+ "particuliere": { level: -8, label: "Particulières" },
+ "specialisee": { level: -11, label: "Spécialisées" },
+ "connaissance": { level: -11, label: "Connaissances" },
+ "draconic": { level: -11, label: "Draconics" },
+ "melee": { level: -6, label: "Mêlée" },
+ "tir": { level: -8, label: "Tir" },
+ "lancer": { level: -8, label: "Lancer" }
}
/* -------------------------------------------- */
@@ -267,10 +267,7 @@ export class RdDUtility {
/* -------------------------------------------- */
static checkNull(items) {
- if (items && items.length) {
- return items;
- }
- return [];
+ return items ?? [];
}
/* -------------------------------------------- */
@@ -296,32 +293,40 @@ export class RdDUtility {
}
/* -------------------------------------------- */
- static filterItemsPerTypeForSheet(data) {
- data.data.materiel = this.checkNull(data.itemsByType['objet']);
- data.data.conteneurs = this.checkNull(data.itemsByType['conteneur']);
- data.data.armes = this.checkNull(data.itemsByType['arme']);
- data.data.armures = this.checkNull(data.itemsByType['armure']);
- data.data.livres = this.checkNull(data.itemsByType['livre']);
- data.data.potions = this.checkNull(data.itemsByType['potion']);
- data.data.ingredients = this.checkNull(data.itemsByType['ingredient']);
- data.data.munitions = this.checkNull(data.itemsByType['munition']);
- data.data.herbes = this.checkNull(data.itemsByType['herbe']);
- data.data.sorts = this.checkNull(data.itemsByType['sort']);
- data.data.queues = this.checkNull(data.itemsByType['queue']);
- data.data.souffles = this.checkNull(data.itemsByType['souffle']);
- data.data.ombres = this.checkNull(data.itemsByType['ombre']);
- data.data.tetes = this.checkNull(data.itemsByType['tete']);
- data.data.taches = this.checkNull(data.itemsByType['tache']);
- data.data.monnaie = this.checkNull(data.itemsByType['monnaie']);
- data.data.meditations = this.checkNull(data.itemsByType['meditation']);
- data.data.chants = this.checkNull(data.itemsByType['chant']);
- data.data.danses = this.checkNull(data.itemsByType['danse']);
- data.data.musiques = this.checkNull(data.itemsByType['musique']);
- data.data.oeuvres = this.checkNull(data.itemsByType['oeuvre']);
- data.data.jeux = this.checkNull(data.itemsByType['jeu']);
- data.data.recettescuisine = this.checkNull(data.itemsByType['recettecuisine']);
- data.data.recettesAlchimiques = this.checkNull(data.itemsByType['recettealchimique']);
- data.data.objets = data.data.conteneurs.concat(data.data.materiel).concat(data.data.armes).concat(data.data.armures).concat(data.data.munitions).concat(data.data.livres).concat(data.data.potions).concat(data.data.herbes).concat(data.data.ingredients);
+ static filterItemsPerTypeForSheet(sheetData) {
+
+ sheetData.items.materiel = this.checkNull(sheetData.items['objet']);
+ sheetData.items.conteneurs = this.checkNull(sheetData.items['conteneur']);
+ sheetData.items.armes = this.checkNull(sheetData.items['arme']);
+ sheetData.items.armures = this.checkNull(sheetData.items['armure']);
+ sheetData.items.livres = this.checkNull(sheetData.items['livre']);
+ sheetData.items.potions = this.checkNull(sheetData.items['potion']);
+ sheetData.items.ingredients = this.checkNull(sheetData.items['ingredient']);
+ sheetData.items.munitions = this.checkNull(sheetData.items['munition']);
+ sheetData.items.herbes = this.checkNull(sheetData.items['herbe']);
+ sheetData.items.sorts = this.checkNull(sheetData.items['sort']);
+ sheetData.items.queues = this.checkNull(sheetData.items['queue']);
+ sheetData.items.souffles = this.checkNull(sheetData.items['souffle']);
+ sheetData.items.ombres = this.checkNull(sheetData.items['ombre']);
+ sheetData.items.tetes = this.checkNull(sheetData.items['tete']);
+ sheetData.items.taches = this.checkNull(sheetData.items['tache']);
+ sheetData.items.monnaie = this.checkNull(sheetData.items['monnaie']);
+ sheetData.items.meditations = this.checkNull(sheetData.items['meditation']);
+ sheetData.items.chants = this.checkNull(sheetData.items['chant']);
+ sheetData.items.danses = this.checkNull(sheetData.items['danse']);
+ sheetData.items.musiques = this.checkNull(sheetData.items['musique']);
+ sheetData.items.oeuvres = this.checkNull(sheetData.items['oeuvre']);
+ sheetData.items.jeux = this.checkNull(sheetData.items['jeu']);
+ sheetData.items.recettescuisine = this.checkNull(sheetData.items['recettecuisine']);
+ sheetData.items.recettesAlchimiques = this.checkNull(sheetData.items['recettealchimique']);
+ sheetData.items.objets = sheetData.items.conteneurs.concat(sheetData.items.materiel)
+ .concat(sheetData.items.armes)
+ .concat(sheetData.items.armures)
+ .concat(sheetData.items.munitions)
+ .concat(sheetData.items.livres)
+ .concat(sheetData.items.potions)
+ .concat(sheetData.items.herbes)
+ .concat(sheetData.items.ingredients);
}
/* -------------------------------------------- */
@@ -352,16 +357,16 @@ export class RdDUtility {
}
/* -------------------------------------------- */
- static buildArbreDeConteneur(actorSheet, data) {
+ static buildArbreDeConteneur(actorSheet, sheetData) {
actorSheet.objetVersConteneur = {}; // Table de hash locale pour recupération rapide du conteneur parent (si existant)
// Attribution des objets aux conteneurs
- for (let conteneur of data.data.conteneurs) {
+ for (let conteneur of sheetData.items.conteneurs) {
conteneur.subItems = [];
if (!conteneur.data.encTotal) conteneur.data.encTotal = 0;
//conteneur.data.encTotal = ; Deja calculé
if (conteneur.data.contenu) {
for (let id of conteneur.data.contenu) {
- let objet = data.data.objets.find(objet => (id == objet._id));
+ let objet = sheetData.items.objets.find(objet => (id == objet._id));
if (objet) {
if (!objet.data.encombrement) objet.data.encombrement = 0; // Auto-fix
objet.estContenu = true; // Permet de filtrer ce qifui est porté dans le template
@@ -373,8 +378,8 @@ export class RdDUtility {
}
}
// Construit la liste des conteneurs de niveau 1 (c'est à dire non contenu eux-même dans un conteneur)
- let newConteneurs = data.data.conteneurs.filter(function (conteneur, index, arr) { return !conteneur.estContenu });
- data.data.conteneurs = newConteneurs;
+ let newConteneurs = sheetData.items.conteneurs.filter(function (conteneur, index, arr) { return !conteneur.estContenu });
+ sheetData.items.conteneurs = newConteneurs;
//console.log(newConteneurs);
}
@@ -406,10 +411,10 @@ export class RdDUtility {
static getCategorieCompetences() {
return categorieCompetences;
}
- static getLevelCategory(category) {
+ static getCategorieNiveauBase(category) {
return categorieCompetences[category].level;
}
- static getLabelCategory(category) {
+ static getCategorieLabel(category) {
return categorieCompetences[category].label;
}
static getCaracArray() {
@@ -597,28 +602,16 @@ export class RdDUtility {
}
/* -------------------------------------------- */
- static async loadCompendiumNames(compendium) {
+ static async loadCompendiumData(compendium) {
const pack = game.packs.get(compendium);
- let competences;
- await pack.getIndex().then(index => competences = index);
+ let competences = pack.index;
return competences;
}
/* -------------------------------------------- */
static async loadCompendium(compendium, filter = item => true) {
- let compendiumItems = await RdDUtility.loadCompendiumNames(compendium);
-
- const pack = game.packs.get(compendium);
- let list = [];
- for (let compendiumItem of compendiumItems) {
- await pack.getEntity(compendiumItem._id).then(it => {
- const item = it.data;
- if (filter(item)) {
- list.push(item);
- }
- });
- };
- return list;
+ let compendiumData = await RdDUtility.loadCompendiumData(compendium);
+ return compendiumData.filter(filter);
}
/* -------------------------------------------- */
@@ -687,20 +680,6 @@ export class RdDUtility {
});
}
- /* -------------------------------------------- */
- static createMonnaie(name, valeur_deniers, img = "", enc = 0.01) {
- let piece = {
- name: name, type: 'monnaie', img: img, _id: randomID(16),
- data: {
- quantite: 0,
- valeur_deniers: valeur_deniers,
- encombrement: enc,
- description: ""
- }
- }
- return piece;
- }
-
/* -------------------------------------------- */
static afficherDemandePayer(som1, som2) {
som1 = (som1) ? som1.toLowerCase() : "0d";
@@ -781,7 +760,7 @@ export class RdDUtility {
label: "Supprimer l'objet",
callback: () => {
console.log("Delete : ", itemId);
- actorSheet.actor.deleteOwnedItem(itemId);
+ actorSheet.actor.deleteEmbeddedDocuments('Item', [itemId]);
li.slideUp(200, () => actorSheet.render(false));
}
},
diff --git a/module/rolldata-ajustements.js b/module/rolldata-ajustements.js
index 049b0972..c6372bbc 100644
--- a/module/rolldata-ajustements.js
+++ b/module/rolldata-ajustements.js
@@ -20,7 +20,9 @@ export const referenceAjustements = {
competence: {
isUsed: (rollData, actor) => rollData.competence,
getLabel: (rollData, actor) => rollData.competence?.name,
- getValue: (rollData, actor) => rollData.competence?.data?.niveau,
+ getValue: (rollData, actor) => {
+ return rollData.competence?.data.niveau;
+ },
},
meditation: {
isUsed: (rollData, actor) => rollData.meditation,
diff --git a/module/tmr-utility.js b/module/tmr-utility.js
index aa0358ef..5d437424 100644
--- a/module/tmr-utility.js
+++ b/module/tmr-utility.js
@@ -1,5 +1,6 @@
import { TMRRencontres } from "./tmr-rencontres.js";
import { Misc } from "./misc.js";
+import { Grammar } from "./grammar.js";
/* -------------------------------------------- */
const TMRMapping = {
@@ -210,24 +211,21 @@ const TMRMapping = {
export const TMRType = {
cite: { name: "cité", genre: "f" },
- sanctuaire: { name: "sanctuaire" },
- plaines: { name: "plaines", genre: "p" },
+ sanctuaire: { name: "sanctuaire", genre: 'm' },
+ plaines: { name: "plaines", genre: "fp" },
pont: { name: "pont", genre: "m" },
- collines: { name: "collines", genre: "p" },
+ collines: { name: "collines", genre: "fp" },
foret: { name: "forêt", genre: "f" },
- monts: { name: "monts", genre: "p" },
+ monts: { name: "monts", genre: "mp" },
desert: { name: "désert", genre: "m" },
fleuve: { name: "fleuve", genre: "m" },
lac: { name: "lac", genre: "m" },
- marais: { name: "marais", genre: "m" },
+ marais: { name: "marais", genre: "mp" },
gouffre: { name: "gouffre", genre: "m" },
necropole: { name: "nécropole", genre: "f" },
desolation: { name: "désolation", genre: "f" }
}
-/* -------------------------------------------- */
-const caseSpecificModes = ["attache", "trounoir", "debordement", "reserve_extensible", "maitrisee"];
-
/* -------------------------------------------- */
const tmrRandomMovePatten =
[{ name: 'top', x: 0, y: -1 },
@@ -295,7 +293,7 @@ export class TMRUtility {
tmr.coord = coord;
tmr.genre = TMRType[tmr.type].genre;
}
- let tmrByType = Misc.classify(Object.values(TMRMapping));
+ let tmrByType = Misc.classify(Object.values(TMRMapping), tmr => tmr.type);
for (const [type, list] of Object.entries(tmrByType)) {
TMRType[type].list = list;
}
@@ -332,7 +330,12 @@ export class TMRUtility {
}
static getTMRLabel(coord) {
- return TMRMapping[coord]?.label ?? (coord+": case inconnue");
+ return TMRMapping[coord]?.label ?? (coord + ": case inconnue");
+ }
+
+ static getTMRDescr(coord) {
+ const tmr = TMRMapping[coord];
+ return Grammar.articleDetermine(tmr.genre) + ' ' + tmr.label;
}
static isCaseHumide(tmr) {
@@ -384,7 +387,7 @@ export class TMRUtility {
currentPos.x = currentPos.x + direction.x;
currentPos.y = currentPos.y + direction.y;
if (this._checkTMRCoord(currentPos.x, currentPos.y)) { // Sortie de carte ! Ré-insertion aléatoire
- coord = TMRUtility.getTMR(TMRUtility.convertToTMRCoord(currentPos));
+ coord = TMRUtility.getTMR(TMRUtility.convertToTMRCoord(currentPos));
} else {
coord = await actor.reinsertionAleatoire('Sortie de carte');
}
@@ -435,7 +438,7 @@ export class TMRUtility {
return reserveList.filter(it => TMRUtility.getTMR(it.coord).type == 'fleuve');
}
// Reserve sur un case "normale"
- return reserveList.filter(it => it.coord == coord);
+ return reserveList.filter(it => it.coord == coord);
}
/* -------------------------------------------- */
@@ -450,9 +453,8 @@ export class TMRUtility {
for (let dy = -portee; dy <= portee; dy++) { // Loop thru lines
const currentPos = { x: centerPos.x + dx, y: centerPos.y + dy };
if (this._checkTMRCoord(currentPos.x, currentPos.y)) { // Coordinate is valie
- let posPicNow = this.computeRealPictureCoordinates(currentPos, tmrConstants);
- let dist = Math.sqrt(Math.pow(posPicNow.x - posPic.x, 2) + Math.pow(posPicNow.y - posPic.y, 2)) / tmrConstants.cellw;
- if (dist < portee + 0.5) {
+ let dist = this.distancePosTMR(centerPos, currentPos);
+ if (dist <= portee) {
caseList.push(this.convertToTMRCoord(currentPos)); // Inside the area
}
}
@@ -460,5 +462,21 @@ export class TMRUtility {
}
return caseList;
}
+
+ static distanceTMR(coord1, coord2) {
+ let pos1 = this.convertToCellPos(coord1);
+ let pos2 = this.convertToCellPos(coord2);
+ return this.distancePosTMR(pos1, pos2);
+ }
+
+ static distancePosTMR(pos1, pos2) {
+ const dx = pos2.x - pos1.x;
+ const dy = pos2.y - pos1.y;
+ const abs_dx = Math.abs(dx);
+ const abs_dy = Math.abs(dy);
+ const distance = Math.sign(dx) == Math.sign(dy) ? Math.max(abs_dx, abs_dy) : (abs_dx + abs_dy);
+ return distance;
+ }
+
}
diff --git a/module/tmr/conquete.js b/module/tmr/conquete.js
index 92d665c4..dd19ea67 100644
--- a/module/tmr/conquete.js
+++ b/module/tmr/conquete.js
@@ -35,11 +35,8 @@ export class Conquete extends Draconique {
await this.createCaseTmr(actor, 'Conquête: ' + conquete.label, conquete, queue._id);
}
- async onConquete(actor, tmr, onRemoveToken) {
- let existants = actor.data.items.filter(it => this.isCase(it, tmr.coord));
- for (let casetmr of existants) {
- await actor.deleteOwnedItem(casetmr.data.sourceid);
- onRemoveToken(tmr, casetmr);
- }
+ async onActorDeleteCaseTmr(actor, casetmr) {
+ await actor.deleteEmbeddedDocuments('Item', [casetmr.data.sourceid]);
}
+
}
diff --git a/module/tmr/desorientation.js b/module/tmr/desorientation.js
index f2dad665..1dcec96a 100644
--- a/module/tmr/desorientation.js
+++ b/module/tmr/desorientation.js
@@ -24,10 +24,6 @@ export class Desorientation extends Draconique {
return Object.keys(TMRType).filter(it => !dejaDesorientes.includes(it));
}
- async onActorDeleteOwned(actor, souffle) {
- await this._supprimerCasesTmr(actor, souffle);
- }
-
code() { return 'desorientation' }
tooltip(linkData) { return `Désorientation, cette case n'existe plus !` }
img() { return 'icons/svg/explosion.svg' }
@@ -51,11 +47,5 @@ export class Desorientation extends Draconique {
}
}
- async _supprimerCasesTmr(actor, souffle) {
- let caseTmrs = actor.data.items.filter(it => it.data.sourceId == souffle._id);
- for (let casetmr of caseTmrs) {
- await actor.deleteOwnedItem(casetmr._id);
- }
- }
}
diff --git a/module/tmr/draconique.js b/module/tmr/draconique.js
index 9af391ec..3d10df82 100644
--- a/module/tmr/draconique.js
+++ b/module/tmr/draconique.js
@@ -7,8 +7,7 @@ const registeredEffects = [
/**
* Définition des informations d'une "draconique" (queue, ombre, tête, souffle) qui influence les TMR
*/
-export class Draconique
-{
+export class Draconique {
static isCaseTMR(element) { return element.type == 'casetmr'; }
static isQueueDragon(element) { return element.type == 'queue' || element.type == 'ombre'; }
static isSouffleDragon(element) { return element.type == 'souffle'; }
@@ -16,6 +15,7 @@ export class Draconique
static isQueueSouffle(it) { return Draconique.isQueueDragon(it) || Draconique.isSouffleDragon(it); }
tmrLabel(linkData) { return TMRUtility.getTMRLabel(linkData.data.coord); }
+ tmrDescr(linkData) { return TMRUtility.getTMRDescr(linkData.data.coord); }
static register(draconique) {
registeredEffects[draconique.code()] = draconique;
@@ -28,6 +28,7 @@ export class Draconique
static all() {
return Object.values(registeredEffects);
}
+
static get(code) {
return registeredEffects[code];
}
@@ -56,10 +57,11 @@ export class Draconique
}
async onActorDeleteOwned(actor, item) {
- let caseTmrs = actor.data.items.filter(it => this.isCase(it) && it.data.sourceid == item._id);
- for (let casetmr of caseTmrs) {
- await actor.deleteOwnedItem(casetmr._id);
- }
+ this.deleteCasesTmr(actor, item);
+ return false;
+ }
+
+ async onActorDeleteCaseTmr(actor, casetmr) {
return false;
}
/**
@@ -72,7 +74,7 @@ export class Draconique
* @returns un tooltip à afficher au dessus du token
*/
tooltip(linkData) { return undefined }
-
+
/**
* @param {*} img l'url du fichier image à utiliser pour le token. Si indéfini (et si createSprite n'est pas surchargé),
* un disque est utilisé.
@@ -102,7 +104,7 @@ export class Draconique
if (this.img()) {
return pixiTMR.sprite(this.code());
}
- else{
+ else {
return pixiTMR.circle()
}
}
@@ -120,11 +122,21 @@ export class Draconique
return list.find(c => this.isCase(c, coord));
}
- async createCaseTmr(actor, label, tmr, sourceId=undefined) {
- await actor.createOwnedItem({
+ async createCaseTmr(actor, label, tmr, sourceId = undefined) {
+ await actor.createEmbeddedDocuments('Item', [{
name: label, type: 'casetmr', img: this.img(), _id: randomID(16),
- data: { coord: tmr.coord, specific: this.code(), sourceid:sourceId }
- });
+ data: { coord: tmr.coord, specific: this.code(), sourceid: sourceId }
+ }]);
}
+ async deleteCasesTmr(actor, draconique) {
+ let caseTmrs = actor.data.items.filter(it => this.isCase(it) && it.data.sourceid == draconique._id);
+ await actor.deleteEmbeddedDocuments('Item', caseTmrs.map(it =>it._id));
+ }
+
+ async onVisiteSupprimer(actor, tmr, onRemoveToken) {
+ let existants = actor.data.items.filter(it => this.isCase(it, tmr.coord));
+ await actor.deleteEmbeddedDocuments('Item', [ existants.map(it => it._id)]);
+ existants.forEach(it => onRemoveToken(tmr, it));
+ }
}
\ No newline at end of file
diff --git a/module/tmr/effets-draconiques.js b/module/tmr/effets-draconiques.js
index ab8bdc3d..6eefe7f3 100644
--- a/module/tmr/effets-draconiques.js
+++ b/module/tmr/effets-draconiques.js
@@ -14,6 +14,8 @@ import { PresentCites } from "./present-cites.js";
import { Desorientation } from "./desorientation.js";
import { Conquete } from "./conquete.js";
import { Pelerinage } from "./pelerinage.js";
+import { Periple } from "./periple.js";
+import { UrgenceDraconique } from "./urgence-draconique.js";
export class EffetsDraconiques {
@@ -32,6 +34,8 @@ export class EffetsDraconiques {
static desorientation = new Desorientation();
static conquete = new Conquete();
static pelerinage = new Pelerinage();
+ static periple = new Periple();
+ static urgenceDraconique = new UrgenceDraconique();
static init() {
Draconique.register(EffetsDraconiques.carteTmr);
@@ -49,6 +53,8 @@ export class EffetsDraconiques {
Draconique.register(EffetsDraconiques.desorientation);
Draconique.register(EffetsDraconiques.conquete);
Draconique.register(EffetsDraconiques.pelerinage);
+ Draconique.register(EffetsDraconiques.periple);
+ Draconique.register(EffetsDraconiques.urgenceDraconique);
}
/* -------------------------------------------- */
@@ -112,8 +118,7 @@ export class EffetsDraconiques {
}
static isPeriple(element) {
- // TODO
- return EffetsDraconiques.isMatching(element, it => Draconique.isSouffleDragon(it) && ir.name.toLowerCase() == 'périple');
+ return EffetsDraconiques.isMatching(element, it => EffetsDraconiques.periple.match(it));
}
static isDesorientation(element) {
@@ -122,7 +127,19 @@ export class EffetsDraconiques {
/* -------------------------------------------- */
static isSortImpossible(element) {
- return EffetsDraconiques.isMatching(element, it => EffetsDraconiques.conquete.match(it) || EffetsDraconiques.pelerinage.match(it));
+ return EffetsDraconiques.isMatching(element, it =>
+ EffetsDraconiques.conquete.match(it) ||
+ EffetsDraconiques.periple.match(it) ||
+ EffetsDraconiques.urgenceDraconique.match(it) ||
+ EffetsDraconiques.pelerinage.match(it)
+ );
+ }
+ static isSortReserveImpossible(element) {
+ return EffetsDraconiques.isMatching(element, it =>
+ EffetsDraconiques.conquete.match(it) ||
+ EffetsDraconiques.periple.match(it) ||
+ EffetsDraconiques.pelerinage.match(it)
+ );
}
static isConquete(element) {
@@ -138,7 +155,7 @@ export class EffetsDraconiques {
}
static isUrgenceDraconique(element) {
- return EffetsDraconiques.isMatching(element, it => Draconique.isQueueDragon(it) && it.name.toLowerCase() == 'urgence draconique');
+ return EffetsDraconiques.isMatching(element, it => EffetsDraconiques.urgenceDraconique.match(it));
}
/* -------------------------------------------- */
diff --git a/module/tmr/fermeture-cites.js b/module/tmr/fermeture-cites.js
index 6a8602d3..8d695ae6 100644
--- a/module/tmr/fermeture-cites.js
+++ b/module/tmr/fermeture-cites.js
@@ -35,11 +35,4 @@ export class FermetureCites extends Draconique {
await this.createCaseTmr(actor, 'Fermeture: ' + tmr.label, tmr, souffle._id);
}
}
-
- async onConquete(actor, tmr, onRemoveToken) {
- const citeFermee = actor.data.items.find(it => this.isCase(it, tmr.coord));
- await actor.deleteOwnedItem(citeFermee._id);
- onRemoveToken(tmr, citeFermee);
- }
-
}
diff --git a/module/tmr/pelerinage.js b/module/tmr/pelerinage.js
index 76cc2fe9..0da79c9d 100644
--- a/module/tmr/pelerinage.js
+++ b/module/tmr/pelerinage.js
@@ -31,12 +31,8 @@ export class Pelerinage extends Draconique {
});
}
- async onFinPelerinage(actor, tmr, onRemoveToken) {
- const pelerinages = actor.data.items.filter(it => this.isCase(it, tmr.coord));
- for (let p of pelerinages){
- await actor.deleteOwnedItem(p.data.sourceid);
- onRemoveToken(tmr, p);
- }
+ async onActorDeleteCaseTmr(actor, casetmr) {
+ await actor.deleteEmbeddedDocuments('Item', [casetmr.data.sourceid]);
}
}
diff --git a/module/tmr/periple.js b/module/tmr/periple.js
new file mode 100644
index 00000000..feba1a2b
--- /dev/null
+++ b/module/tmr/periple.js
@@ -0,0 +1,44 @@
+import { Grammar } from "../grammar.js";
+import { tmrColors, tmrConstants, tmrTokenZIndex, TMRUtility } from "../tmr-utility.js";
+import { Draconique } from "./draconique.js";
+
+export class Periple extends Draconique {
+
+ constructor() {
+ super();
+ }
+
+ type() { return 'souffle' }
+ match(item) { return Draconique.isSouffleDragon(item) && Grammar.toLowerCaseNoAccent(item.name).includes('periple'); }
+ manualMessage() { return false }
+
+ async onActorCreateOwned(actor, souffle) {
+ let terrain = new Roll("1d2").evaluate().total == 1 ? 'sanctuaire' : 'necropole';
+ let tmrs = TMRUtility.getListTMR(terrain);
+ for (let tmr of tmrs) {
+ await this.createCaseTmr(actor, 'Périple: ' + tmr.label, tmr, souffle._id);
+ }
+ }
+
+
+ code() { return 'periple' }
+ tooltip(linkData) { return `Votre Périple passe par ${this.tmrDescr(linkData)}` }
+ img() { return 'icons/svg/acid.svg' }
+
+ createSprite(pixiTMR) {
+ return pixiTMR.sprite(this.code(), {
+ zIndex: tmrTokenZIndex.conquete,
+ alpha: 1,
+ color: tmrColors.souffle,
+ taille: tmrConstants.twoThird,
+ decallage: tmrConstants.right
+ });
+ }
+ getDifficulte(tmr) {
+ switch (tmr.type) {
+ case 'sanctuaire': return -3;
+ case 'necropole': return -5;
+ }
+ return 0;
+ }
+}
\ No newline at end of file
diff --git a/module/tmr/present-cites.js b/module/tmr/present-cites.js
index c6967b94..9ec7d717 100644
--- a/module/tmr/present-cites.js
+++ b/module/tmr/present-cites.js
@@ -60,6 +60,6 @@ export class PresentCites extends Draconique {
}
async ouvrirLePresent(actor, casetmr) {
- await actor.deleteOwnedItem(casetmr._id);
+ await actor.deleteEmbeddedDocuments('Item', [casetmr._id]);
}
}
diff --git a/module/tmr/urgence-draconique.js b/module/tmr/urgence-draconique.js
new file mode 100644
index 00000000..417ec380
--- /dev/null
+++ b/module/tmr/urgence-draconique.js
@@ -0,0 +1,55 @@
+import { ChatUtility } from "../chat-utility.js";
+import { Grammar } from "../grammar.js";
+import { Misc } from "../misc.js";
+import { RdDRollTables } from "../rdd-rolltables.js";
+import { tmrColors, tmrConstants, tmrTokenZIndex, TMRUtility } from "../tmr-utility.js";
+import { Draconique } from "./draconique.js";
+
+export class UrgenceDraconique extends Draconique {
+
+ constructor() {
+ super();
+ }
+
+ type() { return 'queue' }
+ match(item) { return Draconique.isQueueDragon(item) && Grammar.toLowerCaseNoAccent(item.name).includes('urgence draconique'); }
+ manualMessage() { return false }
+ async onActorCreateOwned(actor, queue) {
+ let coordSortsReserve = (actor.data.data.reve.reserve?.list.map(it => it.coord)) ?? [];
+ if (coordSortsReserve.length == 0) {
+ // La queue se transforme en idée fixe
+ let ideeFixe = await RdDRollTables.getIdeeFixe();
+ ChatMessage.create({
+ whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
+ content: `En l'absence de sorts en réserve, l'urgence draconique de ${actor.name} se transforme en ${queue.name}`
+ });
+ await actor.createEmbeddedDocuments('Item', [ideeFixe]);
+ await actor.deleteEmbeddedDocuments('Item', [queue._id]);
+ return;
+ }
+ else {
+ let demiReve = actor.getDemiReve();
+ coordSortsReserve.sort((a, b) => TMRUtility.distanceTMR(a, demiReve) - TMRUtility.distanceTMR(b, demiReve));
+ let tmr = TMRUtility.getTMR(coordSortsReserve[0]);
+ await this.createCaseTmr(actor, 'Urgence draconique: ' + tmr.label, tmr, queue._id);
+ }
+ }
+
+ async onActorDeleteCaseTmr(actor, casetmr) {
+ await actor.deleteEmbeddedDocuments('Item', [casetmr.data.sourceid]);
+ }
+
+ code() { return 'urgence' }
+ tooltip(linkData) { return `Urgence draconique!` }
+ img() { return 'icons/svg/hazard.svg' }
+
+ createSprite(pixiTMR) {
+ return pixiTMR.sprite(this.code(),
+ {
+ zIndex: tmrTokenZIndex.conquete,
+ color: tmrColors.queues,
+ taille: tmrConstants.full,
+ decallage: { x: 2, y: 0 }
+ });
+ }
+}
diff --git a/packs/rappel-des-regles.db b/packs/rappel-des-regles.db
index 65ea77b0..5ca0c0b9 100644
--- a/packs/rappel-des-regles.db
+++ b/packs/rappel-des-regles.db
@@ -5,3 +5,4 @@
{"_id":"K42KNuBHizMppV5F","name":"Tourbillon rouge","permission":{"default":0,"jOzRscDxoXZWpGS6":3},"flags":{},"content":"Le Tourbillon rouge est un tourbillon vampire. Il fonctionne comme les Tourbillons blancs et noirs, sauf que chaque round tant qu’il n’est pas maîtrisé fait dériver le demi-rêve de 4 cases, draine 2 points de rêve et 1 point de vie.
\nOn peut se dérober normalement devant ces rencontres ou les refouler. Toutefois, leur refoulement coûte 2 points au lieu d’un, sauf le Tourbillon rouge qui en coûte 3.
"}
{"_id":"ZmMoOtUdgjMd4cNs","name":"Conflit de sens","permission":{"default":0,"jOzRscDxoXZWpGS6":3},"flags":{},"content":"Chaque fois que le spectateur d’une illusion visuelle est en proie à un conflit de sens, c’est-à-dire quand il y a contradiction ou impossibilité entre ce que lui indiquent ses autres sens et sa vue, l’illusion suscite une brume limbaire. C’est une sorte de flou ectoplasmique de couleur gris vert (comme les Limbes) qui restitue la logique à défaut de restituer la réalité. La brume limbaire a la taille et la forme approximative de la chose réelle.
\nSoit par exemple une porte rendue invisible. Puisqu’elle \"n’existe pas\", on devrait voir soit la continuation du mur, soit ce qu’il y a de l’autre côté. Or ni l’un ni l’autre ne sont du ressort de l’illusion qui, au pied de la lettre, n’est que porte invisible, et non pas invention d’autre chose. Si un spectateur prend conscience de cette anomalie, il voit un rectangle de flou gris-vert se dessiner à la place de la porte, c’est-à-dire ni le mur, ni ce qu’il y a de l’autre côté, ni non plus la porte elle-même. La porte reste donc bien invisible, puisqu’on ne la voit pas, mais pas sa présence. De la même façon, un humanoïde invisible le reste totalement tant qu’il ne commet aucune action ayant pour conséquence un conflit d’interprétation chez un spectateur, auquel cas ce dernier voit apparaître un \"fantôme\" gris-vert justifiant l’action qui vient de se produire. Noter ici aussi que si la présence de l’humanoïde cesse d’être \"invisible\", ce dernier le demeure au sens où son fantôme n’est qu’une silhouette totalement anonyme.
\nLa brume limbaire n’apparaît que pour le spectateur ayant un conflit de sens. Ceux qui ne sont pas victimes d’un tel conflit continuent à voir l’illusion telle qu’elle est. En combat, un attaquant invisible ne suscite une brume limbaire que pour la créature qu’il vient d’attaquer ainsi que pour un témoin ponctuel de l’attaque.
\nCe sont les invisibilités qui sont à même de susciter le plus de conflits de sens, mais c’est également possible pour les deux autres illusions visuelles.
\nDès que les sens cessent d’être en conflit, la brume limbaire s’estompe et l’on retourne à une illusion réelle et totale, invisibilité ou autre.
\nLa brume limbaire n’est suscitée qu’en cas de conflit de sens, pas d’intellect. Un raisonnement ne peut susciter une brume limbaire, uniquement un conflit avec l’un ou l’autre des quatre autres sens, ouïe, toucher, odorat, goût.
\nMoins une illusion sollicite de sens, moins elle a de chances de créer un conflit, et plus elle est donc fiable, voire indétectable. Une illusion qui ne s’adresse qu’à la vue (changement de couleur, changement des lettres d’un texte) marche toujours à 100 %.
\nLes autres illusions, auditives, gustatives et olfactives, ne génèrent jamais de brume limbaire quand bien même elles sont inexplicables.
\nUne cible donnée ne peut recevoir à la fois qu’une seule illusion visuelle, une seule illusion auditive, une seule illusion olfactive et une seule illusion gustative, soit un maximum de quatre illusions sensorielles différentes.
"}
{"_id":"erO7AICiN1LtRyFg","name":"Magie impossible","permission":{"default":0,"jOzRscDxoXZWpGS6":3},"flags":{},"content":"Tout cas de magie impossible résulte immédiatement en une déchirure du rêve ayant le haut-rêvant pour centre.
\nElle peut être violette (déchirure de départ) ou jaune (déchirure d’arrivée). C’est au gardien des rêves de le décider ou de le tirer au sort.
\nSes dimensions peuvent faire jusqu’à 100 m de diamètre, à décider ou tirer par le gardien des rêves.
\nElle peut ne durer que quelques instants avant de se dissoudre, ou durer indéfiniment, toujours à la décision du gardien des rêves.
\nDe même, c’est à lui de décider du rêve d’arrivée si c’est une déchirure de départ, ou des créatures qui peuvent en surgir si c’est une déchirure d’arrivée. En cas de déchirure de départ (violette), elle emporte immédiatement tout ce qui ne fait pas partie du paysage : objets et créatures.
\nSeules les constituantes du paysage, végétation, rochers, constructions, demeurent. Noter que si une construction demeure, tous les objets qu’elle contient, meubles et autres, disparaissent.
"}
+{"_id":"7uGrUHGdPu0EmIu2","name":"Documentation MJ/Joueurs","content":"Préambule
\nCe système pour Foundry est une implémentation de Rêve de Dragon, un jeu de Denis Gerfaud, publié dans sa troisième édition par \"Le Scriptarium\". Rêve de Dragon est une marque déposée par \"Scriptarium\". Tous les droits leur en reviennent naturellement.
\nMerci à Scriptarium (Jidus et Roland Barthelémy) pour l'autorisation d'utilisation des silhouettes de créatures et les Terres Médianes du Rêve.
\nCrédits :
\n\n- Développement : LeRatierBretonnien & VincentVk
\n- Compendiums, tests et relectures : Grendel, VincentVk, Fred, Mickael Nome et Fab
\n- Icones/tokens : Grendel, VincentVk
\n- Graphisme et styles : Mandar, VincentVk
\n
\nPour nous contacter : https://discord.gg/pPSDNJk , channel #reve-de-dragon
\nCréer un Personnage
\nTout se fait manuellement à l'heure actuelle, il convient donc procéder comme suit :
\n\n- débloquer: pour permettre la saisie rapide des caractéristiques et compétences
\n- Renseignez les caractéristiques dans l'onglet concerné.
\n- Renseignez les niveaux de compétences nécessaires
\n- Ouvrez le compendium de l'équipement et faites glisser/déplacer sur l'équipement que vous souhaitez
\n- Si votre personnage est haut-rêvant, ouvrez le compendium des sorts et faites glisser/déplacer pour attribuer les sorts.
\n- Si votre personnage a des têtes, queues, souffles de dragons, ouvrez le compendium correspondant et faites glisser/déplacer.
\n- se familiariser avec les différents compteurs, modifier le seuil de rêve (onglet Haut Rêve)
\n
\nChaque élément apparaît dans son onglet propre.
\nPour réaliser un jet, il suffit de cliquer sur le nom d'une caractéristique, sur une compétence ou sur un objet. Ce clic ouvre la boite de dialogue des jets, qui permet de paramétrer les différentes options (difficulté, compétence/carac, etc). Le lancer affiche les résultats dans le tchat, avec le résultat, la qualité de la réussite, les points d'expérience éventuels et les points de taches.
\nL'état général du personnage est automatiquement pris en compte.
\nPartie haute
\nLes principaux compteurs (vie, endurance, fatigue et rêve, sonné) sont visibles dans la partie haute. Un clic sur le rêve à cet endroit permet de faire un jet de points actuels de rêve (par exemple, un jet de résistance).
\nPlusieurs boutons sont disponibles:
\n\n- Encaisser des dommages
\n- Remise à neuf (Uniquement pour le MJ) pour enlever toutes les blessures/états du personnage.
\n- Dormir une heure (récupération de rêve, fatigue, endurance)
\n- Chateau Dormant pour la dernière heure de la nuit (récupération des blessures, stress, ...)
\n- Montée dans les Terres Médianes
\n- Montée rapide
\n- Regarder ses terres médianes (sans monter)
\n
\nCombat
\nPour l'initiative et les attaques, des options sont disponibles sur le token (menu contextuel).
\nUne fois l'initiative réglée, l'attaquant sélectionne sa cible, puis utilise l'option d'attaque avec cette arme souhaitée (il peut aussi utiliser l'arme dans la feuille de persionnage). La fenêtre de jet de résolution est alors ouverte pour choisir sa difficulté libre, et différents ajustements liés aux conditions et tactiques.
\nSi l'attaque réussit, le défenseur recevra un message dans le tchat avec ses actions de défense -ou d'encaissement- disponibles, selon ses compétences : Encaisser, Esquiver, Parer, ...
\nUn click sur ces actions génère le jet de riposte et produit les résultats. En cas d'échec, le défenseur aura de nouveau un message lui demandant d'encaisser, pour lui donner l'opportunité de faire appel à la chance ou à la destinée.
\nSi décidément ce nb'est pas son jour, il peut cliquer sur le lien pour encaisser, les blessures et l'état général sont automatiquement mis à jour.
\nHaut Rêve
\nLes sorts peuvent être ajoutés depuis le compendium correspondant (par voie de Draconic). La description des sorts est disponible en cliquant sur le sort.
\nPour monter dans les Terres Médianes, il suffit de cliquer sur l'un des boutons \"Monter dans les Terres Médianes!\" sur la feuille de personnage.
\nLa fiche des TMR apparait alors, vous permettant de vous déplacer. Le point de rêve de montée, la fatigue, les rencontres, les cases humides sont automatiquement gérés. Lorsque vous êtes sur la bonne case, il vous suffit de cliquer sur 'Lancer le sort', qui ouvre la boite de dialogue du lancement.
\nDivers
\nCertains raccourcis de commandes sont disponibles directement dans le tchat:
\n\n/table [table]
: effectue un tirage sur la table correspondante (queues, ombres, tete, tetehr, souffle, tarot) \n/table rdd
: ouvre la table de résolution \n/tmra
: Tire une case aléatoire des TMR \n/tmrr [type de case] [1-100]
: détermine la rencontre correspondant au jet de dés pour le type de case \n
\nCe qui n'est pas implémenté/en cours
\n\n- Rendre plus jolie les feuilles de perso
\n- Rendre plus jolis les messages du système de jeu
\n- Les combats d'empoignade (et certaines spécificités du pugilat)
\n- Des messages pour le MJ sur certaines actions des joueurs, pour le prévenir (TMR notamment)
\n- Les retours que vous nous ferez ;-)
\n
\n","img":null,"folder":"","sort":0,"permission":{"default":0,"Q4cUvqxCxMoTJXDL":3},"flags":{}}
diff --git a/styles/simple.css b/styles/simple.css
index fb4342b2..8e5ece73 100644
--- a/styles/simple.css
+++ b/styles/simple.css
@@ -521,7 +521,7 @@ section.sheet-body:after {
width: 50px;
}
-#vie-plus, #vie-moins, #endurance-plus, #endurance-moins, #fatigue-plus, #fatigue-moins, #ptreve-actuel-plus, #ptreve-actuel-moins, .monnaie-plus, .monnaie-moins {
+.ajustement-compteur {
display: inline-block;
width: 1.25rem;
background: rgba(30, 25, 20, 1);
diff --git a/system.json b/system.json
index 70076bb4..db7d71f6 100644
--- a/system.json
+++ b/system.json
@@ -2,10 +2,10 @@
"name": "foundryvtt-reve-de-dragon",
"title": "Rêve de Dragon",
"description": "Rêve de Dragon RPG for FoundryVTT",
- "version": "1.3.25",
+ "version": "1.4.0",
"manifestPlusVersion": "1.0.0",
- "minimumCoreVersion": "0.7.5",
- "compatibleCoreVersion": "0.7.9",
+ "minimumCoreVersion": "0.8.0",
+ "compatibleCoreVersion": "0.8.0",
"templateVersion": 95,
"author": "LeRatierBretonnien",
"authors": [
diff --git a/templates/actor-creature-sheet.html b/templates/actor-creature-sheet.html
index 1901d9eb..807e1c15 100644
--- a/templates/actor-creature-sheet.html
+++ b/templates/actor-creature-sheet.html
@@ -1,3 +1,4 @@
+{{log "handlebar" this}}