Merge branch 'v1.4-signes-draconiques' into 'v1.4'

Gestion des signes draconiques

See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!239
This commit is contained in:
Leratier Bretonnien 2021-05-16 20:42:40 +00:00
commit 4715a75d0b
44 changed files with 1026 additions and 347 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@
.idea .idea
todo.txt todo.txt
todo.md todo.md
/.vscode

BIN
icons/heures/de-heures.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@ -223,6 +223,11 @@ export class RdDActorSheet extends ActorSheet {
const item = this.actor.items.get(li.data("item-id")); const item = this.actor.items.get(li.data("item-id"));
item.sheet.render(true); item.sheet.render(true);
}); });
html.find('.display-label a').click((event) => {
let myID = event.currentTarget.attributes['data-item-id'].value;
const item = this.actor.getEmbeddedDocument('Item', myID);
item.sheet.render(true);
});
html.find('.rencontre-delete').click(ev => { html.find('.rencontre-delete').click(ev => {
const li = $(ev.currentTarget).parents(".item"); const li = $(ev.currentTarget).parents(".item");
const rencontreKey = li.data("item-id"); const rencontreKey = li.data("item-id");
@ -428,26 +433,6 @@ export class RdDActorSheet extends ActorSheet {
html.find('.enlever-tous-effets').click((event) => { html.find('.enlever-tous-effets').click((event) => {
this.actor.enleverTousLesEffets(); this.actor.enleverTousLesEffets();
}); });
// Display info about queue
html.find('.queuesouffle-label a').click((event) => {
let myID = event.currentTarget.attributes['data-item-id'].value;
const item = this.actor.getEmbeddedDocument('Item', myID);
item.sheet.render(true);
});
// Info sort
html.find('.sort-label a').click((event) => {
let myID = event.currentTarget.attributes['data-id'].value;
const item = this.actor.getEmbeddedDocument('Item', myID);
item.sheet.render(true);
});
// Info sort
html.find('.case-label a').click((event) => {
let myID = event.currentTarget.attributes['data-id'].value;
const item = this.actor.getEmbeddedDocument('Item', myID);
item.sheet.render(true);
});
// Display info about queue
html.find('.conteneur-name a').click((event) => { html.find('.conteneur-name a').click((event) => {
let myID = event.currentTarget.attributes['data-item-id'].value; let myID = event.currentTarget.attributes['data-item-id'].value;
RdDUtility.toggleAfficheContenu(myID); RdDUtility.toggleAfficheContenu(myID);

View File

@ -19,6 +19,7 @@ import { RdDItemArme } from "./item-arme.js";
import { RdDAlchimie } from "./rdd-alchimie.js"; import { RdDAlchimie } from "./rdd-alchimie.js";
import { StatusEffects } from "./status-effects.js"; import { StatusEffects } from "./status-effects.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js"; import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { RdDItemSigneDraconique } from "./item-signedraconique.js";
import { ReglesOptionelles } from "./regles-optionelles.js"; import { ReglesOptionelles } from "./regles-optionelles.js";
import { TMRRencontres } from "./tmr-rencontres.js"; import { TMRRencontres } from "./tmr-rencontres.js";
import { Poetique } from "./poetique.js"; import { Poetique } from "./poetique.js";
@ -193,7 +194,7 @@ export class RdDActor extends Actor {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
isHautRevant() { isHautRevant() {
return Misc.templateData(this).attributs.hautrevant.value != "" return this.isPersonnage() && Misc.templateData(this).attributs.hautrevant.value != ""
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
getFatigueActuelle() { getFatigueActuelle() {
@ -650,8 +651,7 @@ export class RdDActor extends Actor {
} }
} }
else { else {
const roll = new Roll("1dr").evaluate(); let deRecuperation = await RdDDice.rollTotal("1dr");
let deRecuperation = roll.total;
console.log("recuperationReve", deRecuperation); console.log("recuperationReve", deRecuperation);
if (deRecuperation >= 7) { if (deRecuperation >= 7) {
// Rêve de Dragon ! // Rêve de Dragon !
@ -743,7 +743,7 @@ export class RdDActor extends Actor {
// TODO: un dialogue pour demander le type de tête? // TODO: un dialogue pour demander le type de tête?
rollData.tete = true; rollData.tete = true;
} }
rollData.poesie = Poetique.getExtrait(); rollData.poesie = await Poetique.getExtrait();
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name), whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
@ -1088,11 +1088,17 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */ /* -------------------------------------------- */
computeIsHautRevant() { computeIsHautRevant() {
const tplData = Misc.templateData(this); if (this.isPersonnage()) {
tplData.attributs.hautrevant.value = this.listItemsData('tete').find(it => Grammar.toLowerCaseNoAccent(it.name) == 'don de haut-reve') Misc.templateData(this).attributs.hautrevant.value = this.hasItemNamed('tete', 'don de haut-reve')
? "Haut rêvant" ? "Haut rêvant"
: ""; : "";
} }
}
hasItemNamed(type, name) {
name = Grammar.toLowerCaseNoAccent(name);
return this.listItemsData(type).find(it => Grammar.toLowerCaseNoAccent(it.name) == name);
}
/* -------------------------------------------- */ /* -------------------------------------------- */
async computeEncombrementTotalEtMalusArmure() { async computeEncombrementTotalEtMalusArmure() {
@ -1184,7 +1190,7 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */ /* -------------------------------------------- */
async ajouterRefoulement(value = 1) { async ajouterRefoulement(value = 1) {
let refoulement = Misc.templateData(this).reve.refoulement.value + value; let refoulement = Misc.templateData(this).reve.refoulement.value + value;
let total = new Roll("1d20").evaluate({ async: false }).total; let total = await RdDDice.rollTotal("1d20");
if (total <= refoulement) { if (total <= refoulement) {
refoulement = 0; refoulement = 0;
await this.ajouterSouffle({ chat: true }); await this.ajouterSouffle({ chat: true });
@ -1266,7 +1272,7 @@ export class RdDActor extends Actor {
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name) whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name)
}); });
const innaccessible = this.buildTMRInnaccessible(); const innaccessible = this.buildTMRInnaccessible();
let tmr = TMRUtility.getTMRAleatoire(tmr => !innaccessible.includes(tmr.coord)); let tmr = await TMRUtility.getTMRAleatoire(tmr => !innaccessible.includes(tmr.coord));
this.updateCoordTMR(tmr.coord); this.updateCoordTMR(tmr.coord);
this.cacheTMR(); this.cacheTMR();
return tmr; return tmr;
@ -1395,25 +1401,6 @@ export class RdDActor extends Actor {
return RdDCarac.calculSConst(Misc.templateData(this).carac.constitution.value); return RdDCarac.calculSConst(Misc.templateData(this).carac.constitution.value);
} }
/* -------------------------------------------- */
async testSiSonne(sante, endurance) {
const roll = new Roll("1d20").evaluate();
roll.showDice = true;
RdDDice.show(roll);
let result = {
roll: roll,
sonne: roll.total > endurance || roll.total == 20 // 20 is always a failure
}
if (roll.total == 1) {
await this.ajoutXpConstitution(1); // +1 XP !
ChatMessage.create({ content: `${this.name} a obenu 1 sur son Jet d'Endurance et a gagné 1 point d'Expérience en Constitution. Ce point d'XP a été ajouté automatiquement).` });
}
if (result.sonne) {
await this.setSonne();
sante.sonne.value = true;
}
return result;
}
async ajoutXpConstitution(xp) { async ajoutXpConstitution(xp) {
await this.update({ "data.carac.constitution.xp": Misc.toInt(Misc.templateData(this).carac.constitution.xp) + xp }); await this.update({ "data.carac.constitution.xp": Misc.toInt(Misc.templateData(this).carac.constitution.xp) + xp });
@ -1428,48 +1415,71 @@ export class RdDActor extends Actor {
return this.countBlessures(Misc.templateData(this).blessures[name].liste); return this.countBlessures(Misc.templateData(this).blessures[name].liste);
} }
/* -------------------------------------------- */
async testSiSonne(sante, endurance) {
const result = await this._jetEndurance(endurance);
if (result.roll.total == 1) {
ChatMessage.create({ content: await this._gainXpConstitutionJetEndurance() });
}
sante.sonne.value ||= result.sonne;
return result;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
async jetEndurance() { async jetEndurance() {
let myRoll = new Roll("1d20").roll();
myRoll.showDice = true;
await RdDDice.show(myRoll);
const actorData = Misc.data(this); const actorData = Misc.data(this);
let msgText = "Jet d'Endurance : " + myRoll.total + " / " + actorData.data.sante.endurance.value + "<br>"; const endurance = actorData.data.sante.endurance.value;
if (myRoll.total == 1 || (myRoll.total != 20 && myRoll.total <= actorData.data.sante.endurance.value)) {
msgText += `${this.name} a réussi son Jet d'Endurance !`; const result = await this._jetEndurance(actorData.data.sante.endurance.value)
if (myRoll.total == 1) {
await this.ajoutXpConstitution();
msgText += `et gagne 1 Point d'Experience en Constitution`;
}
} else {
await this.setSonne();
msgText += `${this.name} a échoué son Jet d'Endurance et devient Sonné`;
}
const message = { const message = {
content: msgText, content: "Jet d'Endurance : " + result.roll.total + " / " + endurance + "<br>",
whisper: ChatMessage.getWhisperRecipients(game.user.name) whisper: ChatMessage.getWhisperRecipients(game.user.name)
}; };
if (result.sonne) {
message.content += `${this.name} a échoué son Jet d'Endurance et devient Sonné`;
}
else if (result.roll.total == 1) {
message.content += await this._gainXpConstitutionJetEndurance();
}
else {
message.content += `${this.name} a réussi son Jet d'Endurance !`;
}
ChatMessage.create(message); ChatMessage.create(message);
} }
async _gainXpConstitutionJetEndurance() {
await this.ajoutXpConstitution(1); // +1 XP !
return `${this.name} a obtenu 1 sur son Jet d'Endurance et a gagné 1 point d'Expérience en Constitution. Ce point d'XP a été ajouté automatiquement.`;
}
async _jetEndurance(endurance) {
const roll = await RdDDice.roll("1d20", { showDice: true });
let result = {
roll: roll,
sonne: roll.total > endurance || roll.total == 20 // 20 is always a failure
}
if (result.sonne) {
await this.setSonne();
}
return result;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
async jetVie() { async jetVie() {
let myRoll = new Roll("1d20").roll(); let roll = await RdDDice.roll("1d20", { showDice: true });
myRoll.showDice = true;
await RdDDice.show(myRoll);
const actorData = Misc.data(this); const actorData = Misc.data(this);
let msgText = "Jet de Vie : " + myRoll.total + " / " + actorData.data.sante.vie.value + "<br>"; let msgText = "Jet de Vie : " + roll.total + " / " + actorData.data.sante.vie.value + "<br>";
if (myRoll.total <= actorData.data.sante.vie.value) { if (roll.total <= actorData.data.sante.vie.value) {
msgText += "Jet réussi, pas de perte de point de vie (prochain jet dans 1 round pour 1 critique, SC minutes pour une grave)"; msgText += "Jet réussi, pas de perte de point de vie (prochain jet dans 1 round pour 1 critique, SC minutes pour une grave)";
if (myRoll.total == 1) { if (roll.total == 1) {
msgText += "La durée entre 2 jets de vie est multipliée par 20 (20 rounds pour une critique, SCx20 minutes pour une grave)"; msgText += "La durée entre 2 jets de vie est multipliée par 20 (20 rounds pour une critique, SCx20 minutes pour une grave)";
} }
} else { } else {
msgText += "Jet échoué, vous perdez 1 point de vie"; msgText += "Jet échoué, vous perdez 1 point de vie";
await this.santeIncDec("vie", -1); await this.santeIncDec("vie", -1);
if (myRoll.total == 20) { if (roll.total == 20) {
msgText += "Votre personnage est mort !!!!!"; msgText += "Votre personnage est mort !!!!!";
} }
} }
@ -1582,8 +1592,7 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */ /* -------------------------------------------- */
async jetDeMoral(situation, messageReussi = undefined, messageManque = undefined) { async jetDeMoral(situation, messageReussi = undefined, messageManque = undefined) {
let jetMoral = new Roll("1d20").roll(); let jetMoral = await RdDDice.roll("1d20", { showDice: true });
RdDDice.show(jetMoral);
let moralActuel = Misc.toInt(Misc.templateData(this).compteurs.moral.value); let moralActuel = Misc.toInt(Misc.templateData(this).compteurs.moral.value);
const difficulte = 10 + moralActuel; const difficulte = 10 + moralActuel;
const succes = jetMoral.total <= difficulte; const succes = jetMoral.total <= difficulte;
@ -1687,7 +1696,7 @@ export class RdDActor extends Actor {
RdDResolutionTable.displayRollData(jetVieView, this, 'chat-resultat-ethylisme.html'); RdDResolutionTable.displayRollData(jetVieView, this, 'chat-resultat-ethylisme.html');
if (rollEthylisme.isEchec) { if (rollEthylisme.isEchec) {
let enduranceLostRoll = new Roll("1d6").roll(); let enduranceLostRoll = await RdDDice.roll("1d6");
// enduranceLostRoll.showDice = true; // enduranceLostRoll.showDice = true;
RdDDice.show(enduranceLostRoll); RdDDice.show(enduranceLostRoll);
let enduranceLost = enduranceLostRoll.total; let enduranceLost = enduranceLostRoll.total;
@ -2097,9 +2106,11 @@ export class RdDActor extends Actor {
let draconicList = this.computeDraconicAndSortIndex(sortList); let draconicList = this.computeDraconicAndSortIndex(sortList);
const actorData = Misc.data(this); const actorData = Misc.data(this);
const reve = duplicate(actorData.data.carac.reve);
let rollData = { let rollData = {
forceCarac: { 'reve': duplicate(actorData.data.carac.reve) }, carac: { 'reve': reve },
selectedCarac: duplicate(actorData.data.carac.reve), forceCarac: { 'reve': reve },
selectedCarac: reve,
draconicList: draconicList, draconicList: draconicList,
sortList: sortList, sortList: sortList,
competence: draconicList[0], competence: draconicList[0],
@ -2107,10 +2118,8 @@ export class RdDActor extends Actor {
tmr: TMRUtility.getTMR(coord), tmr: TMRUtility.getTMR(coord),
diffLibre: RdDItemSort.getDifficulte(sortList[0], -7), // Per default at startup diffLibre: RdDItemSort.getDifficulte(sortList[0], -7), // Per default at startup
coutreve: Array(30).fill().map((item, index) => 1 + index), coutreve: Array(30).fill().map((item, index) => 1 + index),
carac: { 'reve': duplicate(actorData.data.carac.reve) }
} }
if (this.currentTMR) this.currentTMR.minimize(); // Hide
const dialog = await RdDRoll.create(this, rollData, const dialog = await RdDRoll.create(this, rollData,
{ {
html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-sort.html', html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-sort.html',
@ -2320,6 +2329,11 @@ export class RdDActor extends Actor {
dialog.render(true); dialog.render(true);
} }
/* -------------------------------------------- */
async _competenceResult(rollData) {
RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-competence.html')
}
/* -------------------------------------------- */ /* -------------------------------------------- */
async creerTacheDepuisLivre(item, options = { renderSheet: true }) { async creerTacheDepuisLivre(item, options = { renderSheet: true }) {
const itemData = Misc.data(item); const itemData = Misc.data(item);
@ -2544,24 +2558,15 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */ /* -------------------------------------------- */
async rollMeditation(id) { async rollMeditation(id) {
let meditation = Misc.data(this.getMeditation(id)); let meditation = Misc.data(this.getMeditation(id));
let competence = Misc.data(this.getCompetence(meditation.data.competence));
competence.data.defaut_carac = "intellect"; // Meditation = tjs avec intellect
let meditationData = { let meditationData = {
competence: competence, competence: duplicate(Misc.data(this.getCompetence(meditation.data.competence))),
meditation: meditation, meditation: duplicate(meditation),
conditionMeditation: { conditionMeditation: { isHeure: false, isVeture: false, isComportement: false, isPurification: false },
isHeure: false,
isVeture: false,
isComportement: false,
isPurification: false,
},
diffConditions: 0, diffConditions: 0,
use: { libre: false, conditions: true, }, use: { libre: false, conditions: true, },
carac: {} carac: { "intellect": Misc.templateData(this).carac.intellect }
}; };
meditationData.carac["intellect"] = Misc.templateData(this).carac["intellect"]; meditationData.competence.data.defaut_carac = "intellect"; // Meditation = tjs avec intellect
console.log("rollMeditation !!!", meditationData);
const dialog = await RdDRoll.create(this, meditationData, const dialog = await RdDRoll.create(this, meditationData,
{ {
@ -2573,7 +2578,7 @@ export class RdDActor extends Actor {
label: "Jet de méditation", label: "Jet de méditation",
callbacks: [ callbacks: [
this.createCallbackExperience(), this.createCallbackExperience(),
{ condition: r => r.rolled.isETotal, action: r => this._meditationETotal(r) }, { condition: r => r.rolled.isEPart, action: r => this._meditationEPart(r) },
{ action: r => this._meditationResult(r) } { action: r => this._meditationResult(r) }
] ]
}); });
@ -2584,27 +2589,92 @@ export class RdDActor extends Actor {
async _meditationResult(meditationData) { async _meditationResult(meditationData) {
this.santeIncDec("fatigue", 2); this.santeIncDec("fatigue", 2);
meditationData.diffLecture = -7; const signeData = RdDItemSigneDraconique.prepareSigneDraconiqueMeditation(meditationData.meditation, meditationData.rolled)
if (meditationData.rolled.isPart) if (signeData) {
meditationData.diffLecture = 0; await this.createEmbeddedDocuments("Item", [signeData]);
else if (meditationData.rolled.isSign) }
meditationData.diffLecture = -3;
RdDResolutionTable.displayRollData(meditationData, this.name, 'chat-resultat-meditation.html'); RdDResolutionTable.displayRollData(meditationData, this.name, 'chat-resultat-meditation.html');
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_meditationETotal(meditationData) { _meditationEPart(meditationData) {
meditationData.meditation.data.malus--; this.updateEmbeddedDocuments('Item', [{ _id: meditation._id, 'data.malus': meditationData.meditation.data.malus - 1 }]);
this.updateEmbeddedDocuments('Item', [meditationData.meditation]); }
/* -------------------------------------------- */
_getSignesDraconiques(coord) {
const type = TMRUtility.getTMRType(coord);
return this.listItemsData("signedraconique").filter(it => it.data.typesTMR.includes(type));
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async _competenceResult(rollData) { isResonanceSigneDraconique(coord) {
RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-competence.html') return this._getSignesDraconiques(coord).length > 0;
} }
async _moralDecrease(rollData) {
RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-competence.html') /* -------------------------------------------- */
async rollLireSigneDraconique(coord) {
if (!this.isHautRevant()) {
ui.notifications.info("Seul un haut rêvant peut lire un signe draconique!");
return;
}
let signes = this._getSignesDraconiques(coord);
if (signes.length == 0) {
ui.notifications.info(`Aucun signe draconiques en ${coord} !`);
return;
}
if (this.currentTMR) this.currentTMR.minimize(); // Hide
let draconicList = this.getDraconicList()
.map(draconic => duplicate(Misc.data(draconic)))
.map(draconic => { draconic.data.defaut_carac = "intellect"; return draconic; });
const intellect = Misc.templateData(this).carac.intellect;
let rollData = {
carac: { 'intellect': intellect },
selectedCarac: intellect,
competence: draconicList[0],
draconicList: draconicList,
signe: signes[0],
signes: signes,
tmr: TMRUtility.getTMR(coord),
diffLibre: Misc.data(signes[0]).data.difficulte,
}
const dialog = await RdDRoll.create(this, rollData,
{
html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-signedraconique.html',
options: { height: 600 },
close: html => { this.currentTMR.maximize() } // Re-display TMR
},
{
name: 'lire-signe-draconique',
label: 'Lire le signe draconique',
callbacks: [
this.createCallbackExperience(),
{ action: r => this._rollLireSigneDraconique(r) }
]
}
);
dialog.render(true);
}
/* -------------------------------------------- */
async _rollLireSigneDraconique(rollData) {
const compData = rollData.competence;
if (!RdDItemCompetence.isDraconic(compData)) {
ui.notifications.error(`La compétence ${compData.name} n'est pas une compétence draconique`);
return;
}
rollData.xpSort = RdDItemSigneDraconique.getXpSortSigneDraconique(rollData.rolled.code, rollData.signe);
if (rollData.xpSort > 0) {
await this.updateEmbeddedDocuments("Item", [{ _id: compData._id, 'data.xp_sort': Misc.toInt(compData.data.xp_sort) + rollData.xpSort }]);
}
await this.deleteEmbeddedDocuments("Item", [rollData.signe._id]);
RdDResolutionTable.displayRollData(rollData, this.name, 'chat-resultat-lecture-signedraconique.html');
this.currentTMR.close();
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -2840,6 +2910,7 @@ export class RdDActor extends Actor {
fatigue: RdDUtility.calculFatigueHtml(fatigue, endurance), fatigue: RdDUtility.calculFatigueHtml(fatigue, endurance),
draconic: this.getDraconicList(), draconic: this.getDraconicList(),
sort: this.getSortList(), sort: this.getSortList(),
signes: this.listItemsData("signedraconique"),
caracReve: actorData.data.carac.reve.value, caracReve: actorData.data.carac.reve.value,
pointsReve: this.getReveActuel(), pointsReve: this.getReveActuel(),
isRapide: isRapide isRapide: isRapide
@ -2904,14 +2975,14 @@ export class RdDActor extends Actor {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
computeArmure(attackerRoll) { async computeArmure(attackerRoll) {
let dmg = (attackerRoll.dmg.dmgArme ?? 0) + (attackerRoll.dmg.dmgActor ?? 0); let dmg = (attackerRoll.dmg.dmgArme ?? 0) + (attackerRoll.dmg.dmgActor ?? 0);
let armeData = attackerRoll.arme; let armeData = attackerRoll.arme;
let protection = 0; let protection = 0;
const armures = this.items.map(it => Misc.data(it)) const armures = this.items.map(it => Misc.data(it))
.filter(it => it.type == "armure" && it.data.equipe); .filter(it => it.type == "armure" && it.data.equipe);
for (const itemData of armures) { for (const itemData of armures) {
protection += new Roll(itemData.data.protection.toString()).roll().total; protection += await RdDDice.rollTotal(itemData.data.protection.toString());
if (dmg > 0) { if (dmg > 0) {
this._deteriorerArmure(itemData, dmg); this._deteriorerArmure(itemData, dmg);
dmg = 0; dmg = 0;
@ -2972,7 +3043,7 @@ export class RdDActor extends Actor {
console.log("encaisserDommages", rollData) console.log("encaisserDommages", rollData)
let santeOrig = duplicate(Misc.templateData(this).sante); let santeOrig = duplicate(Misc.templateData(this).sante);
let encaissement = this.jetEncaissement(rollData); let encaissement = await this.jetEncaissement(rollData);
this.ajouterBlessure(encaissement); // Will upate the result table this.ajouterBlessure(encaissement); // Will upate the result table
const perteVie = this.isEntiteCauchemar() const perteVie = this.isEntiteCauchemar()
@ -3011,29 +3082,34 @@ export class RdDActor extends Actor {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
jetEncaissement(rollData) { async jetEncaissement(rollData) {
const roll = new Roll("2d10").roll(); const roll = await RdDDice.roll("2d10", { showDice: true });
roll.showDice = true;
RdDDice.show(roll, game.settings.get("core", "rollMode"));
const armure = this.computeArmure(rollData); const armure = await this.computeArmure(rollData);
const jetTotal = roll.total + rollData.dmg.total - armure; const jetTotal = roll.total + rollData.dmg.total - armure;
let encaissement = RdDUtility.selectEncaissement(jetTotal, rollData.dmg.mortalite) let encaissement = RdDUtility.selectEncaissement(jetTotal, rollData.dmg.mortalite)
let over20 = Math.max(jetTotal - 20, 0); let over20 = Math.max(jetTotal - 20, 0);
encaissement.dmg = rollData.dmg; encaissement.dmg = rollData.dmg;
encaissement.dmg.loc = rollData.dmg.loc ?? RdDUtility.getLocalisation(this.data.type); encaissement.dmg.loc = rollData.dmg.loc ?? await RdDUtility.getLocalisation(this.data.type);
encaissement.dmg.loc.label = encaissement.dmg.loc.label ?? 'Corps;' encaissement.dmg.loc.label = encaissement.dmg.loc.label ?? 'Corps;'
encaissement.roll = roll; encaissement.roll = roll;
encaissement.armure = armure; encaissement.armure = armure;
encaissement.total = jetTotal; encaissement.total = jetTotal;
encaissement.vie = RdDUtility._evaluatePerte(encaissement.vie, over20); encaissement.vie = await RdDActor._evaluatePerte(encaissement.vie, over20);
encaissement.endurance = RdDUtility._evaluatePerte(encaissement.endurance, over20); encaissement.endurance = await RdDActor._evaluatePerte(encaissement.endurance, over20);
encaissement.penetration = rollData.arme?.data.penetration ?? 0; encaissement.penetration = rollData.arme?.data.penetration ?? 0;
return encaissement; return encaissement;
} }
/* -------------------------------------------- */
static async _evaluatePerte(formula, over20) {
let perte = new Roll(formula, { over20: over20 });
await perte.evaluate({ async: true });
return perte.total;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
ajouterBlessure(encaissement) { ajouterBlessure(encaissement) {
const actorData = Misc.data(this); const actorData = Misc.data(this);
@ -3615,7 +3691,7 @@ export class RdDActor extends Actor {
potionData.reussiteReve = true; potionData.reussiteReve = true;
potionData.aphasiePermanente = false; potionData.aphasiePermanente = false;
if (potionData.data.reposalchimique) { if (potionData.data.reposalchimique) {
let chanceAphasie = new Roll("1d100").evaluate({ async: false }).total; let chanceAphasie = await RdDDice.rollTotal("1d100");
if (chanceAphasie <= potionData.data.pr) { if (chanceAphasie <= potionData.data.pr) {
potionData.aphasiePermanente = true; potionData.aphasiePermanente = true;
} }

View File

@ -0,0 +1,116 @@
import { ChatUtility } from "./chat-utility.js";
import { HtmlUtility } from "./html-utility.js";
import { RdDItemSigneDraconique } from "./item-signedraconique.js";
import { Misc } from "./misc.js";
import { RdDRollTables } from "./rdd-rolltables.js";
import { TMRType, TMRUtility } from "./tmr-utility.js";
export class DialogCreateSigneDraconique extends Dialog {
static async createSigneForActors() {
const signe = await RdDItemSigneDraconique.randomSigneDraconique();
let dialogData = {
signe: signe,
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);
new DialogCreateSigneDraconique(dialogData, html)
.render(true);
}
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(); } }
}
};
super(conf, options);
this.dialogData = dialogData;
}
async _onCreerSigneActeurs() {
this.validerSigne();
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(Misc.data(actor).name),
content: await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/chat-signe-draconique-actor.html", {
signe: signe,
alias: Misc.data(actor).name
})
});
}
validerSigne() {
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.setEphemere(this.dialogData.signe.data.ephemere);
html.find(".signe-aleatoire").click(event => this.setSigneAleatoire());
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));
}
async setSigneAleatoire() {
const newSigne = await RdDItemSigneDraconique.randomSigneDraconique();
$("[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.data.ephemere = ephemere;
HtmlUtility._showControlWhen($(".signe-data-duree"), ephemere);
}
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;
}
};
}
onValeurXpSort(event) {
const codeReussite = event.currentTarget.attributes['data-typereussite']?.value ?? 0;
const xp = Number(event.currentTarget.value);
const oldValeur = this.dialogData.signe.data.valeur;
this.dialogData.signe.data.valeur = RdDItemSigneDraconique.calculValeursXpSort(codeReussite, xp, oldValeur);
}
}

View File

@ -51,8 +51,9 @@ export class RdDItemSheet extends ItemSheet {
/** @override */ /** @override */
setPosition(options = {}) { setPosition(options = {}) {
const position = super.setPosition(options); const position = super.setPosition(options);
const sheetHeader = this.element.find(".sheet-header");
const sheetBody = this.element.find(".sheet-body"); const sheetBody = this.element.find(".sheet-body");
const bodyHeight = position.height - 192; const bodyHeight = position.height - sheetHeader[0].clientHeight;
sheetBody.css("height", bodyHeight); sheetBody.css("height", bodyHeight);
return position; return position;
} }

View File

@ -0,0 +1,104 @@
import { RdDItemSigneDraconique } from "./item-signedraconique.js";
import { Misc } from "./misc.js";
import { TMRType, TMRUtility } from "./tmr-utility.js";
/**
* Item sheet pour signes draconiques
* @extends {ItemSheet}
*/
export class RdDSigneDraconiqueItemSheet extends ItemSheet {
/** @override */
static get defaultOptions() {
return mergeObject(super.defaultOptions, {
classes: ["foundryvtt-reve-de-dragon", "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 */
setPosition(options = {}) {
const position = super.setPosition(options);
const sheetHeader = this.element.find(".sheet-header");
const sheetBody = this.element.find(".sheet-body");
const bodyHeight = position.height - sheetHeader[0].clientHeight;
sheetBody.css("height", bodyHeight);
return position;
}
/* -------------------------------------------- */
async getData() {
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;
}
/* -------------------------------------------- */
/** @override */
activateListeners(html) {
super.activateListeners(html);
if (!this.options.editable) return;
html.find(".signe-aleatoire").click(event => this.setSigneAleatoire());
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();
// $("[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);
this.object.update(newSigne);
}
async onSelectTmr(event) {
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 = Misc.templateData(this.object).valeur;
const newValeur = RdDItemSigneDraconique.calculValeursXpSort(codeReussite, xp, oldValeur);
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}`;
}
}

View File

@ -0,0 +1,100 @@
import { Misc } from "./misc.js";
import { RdDDice } from "./rdd-dice.js";
import { RdDRollTables } from "./rdd-rolltables.js";
import { TMRType } from "./tmr-utility.js";
const tableSignesIndicatifs = [
{ rarete: "Très facile", difficulte: 0, xp: 6, nbCases: 14 },
{ rarete: "Facile", difficulte: -2, xp: 10, nbCases: 10 },
{ rarete: "Moyen", difficulte: -3, xp: 15, nbCases: 7 },
{ rarete: "Difficile", difficulte: -5, xp: 20, nbCases: 4 },
{ rarete: "Ardu", difficulte: -8, xp: 30, nbCases: 1 }
]
export class RdDItemSigneDraconique {
static prepareSigneDraconiqueMeditation(meditation, rolled) {
if (rolled.isSuccess != undefined) {
meditation = Misc.data(meditation);
return {
name: "de la " + meditation.name,
type: "signedraconique",
img: meditation.img,
data: {
"typesTMR": [Misc.upperFirst(meditation.data.tmr)],
"difficulte": RdDItemSigneDraconique.getDiffSigneMeditation(rolled.code),
"ephemere": true,
"duree": "1 round",
"valeur": { "norm": 3, "sign": 5, "part": 10 }
}
};
}
return undefined;
}
static getDiffSigneMeditation(code) {
switch (code) {
case "norm": return -7;
case "sign": return -3;
case "part": return 0;
}
return undefined;
}
static getXpSortSigneDraconique(code, signe) {
return Misc.data(signe).data.valeur[code] ?? 0;
}
static calculValeursXpSort(qualite, valeur, avant) {
switch (qualite) {
case "norm":
return {
norm: valeur,
sign: Math.max(valeur, avant.sign),
part: Math.max(valeur, avant.part)
}
case "sign":
return {
norm: Math.min(valeur, avant.norm),
sign: valeur,
part: Math.max(valeur, avant.part)
}
case "part":
return {
norm: Math.min(valeur, avant.norm),
sign: Math.min(valeur, avant.sign),
part: valeur
}
}
}
static async randomSigneDraconique() {
let modele = await RdDDice.rollOneOf(tableSignesIndicatifs);
return {
name: await RdDItemSigneDraconique.randomSigneDescription(),
type: "signedraconique",
img: 'systems/foundryvtt-reve-de-dragon/icons/tmr/signe_draconique.webp',
data: {
typesTMR: await RdDItemSigneDraconique.randomTmrs(modele.nbCases),
ephemere: true,
duree: "1 round",
difficulte: modele.difficulte,
valeur: { norm: modele.xp, sign: modele.xp, part: Math.floor(modele.xp * 1.5) },
}
};
}
static async randomTmrs(nbTmr = undefined) {
let tmrs = Object.values(TMRType).map(value => Misc.upperFirst(value.name));
let keep = nbTmr ?? (await RdDDice.rollTotal("1d" + TMRType.length) + 1);
for (let i = tmrs.length; i > keep; i--) {
tmrs.splice(await RdDDice.rollTotal("1d" + i), 1);
}
return tmrs;
}
static async randomSigneDescription() {
return await RdDRollTables.drawTextFromRollTable("Signes draconiques", false);
}
}

View File

@ -25,6 +25,7 @@ export class RdDItem extends Item {
isConteneur() { isConteneur() {
return Misc.data(this).type == 'conteneur'; return Misc.data(this).type == 'conteneur';
} }
isVide() { isVide() {
return this.isConteneur() && (Misc.templateData(this).contenu ?? []).length == 0; return this.isConteneur() && (Misc.templateData(this).contenu ?? []).length == 0;
} }

View File

@ -1,3 +1,4 @@
import { RdDDice } from "./rdd-dice.js";
/** /**
* This class is intended as a placeholder for utility methods unrelated * This class is intended as a placeholder for utility methods unrelated
@ -92,10 +93,6 @@ export class Misc {
} }
} }
static rollOneOf(array) {
return array[new Roll("1d" + array.length).evaluate({ async: false }).total - 1];
}
static distinct(array) { static distinct(array) {
return [...new Set(array)]; return [...new Set(array)];
} }

View File

@ -1,4 +1,5 @@
import { Misc } from "./misc.js" import { Misc } from "./misc.js"
import { RdDDice } from "./rdd-dice.js";
const poesieHautReve = [ const poesieHautReve = [
{ {
@ -64,8 +65,8 @@ const poesieHautReve = [
] ]
export class Poetique { export class Poetique {
static getExtrait(){ static async getExtrait(){
return Misc.rollOneOf(poesieHautReve); return await RdDDice.rollOneOf(poesieHautReve);
} }
} }

View File

@ -5,6 +5,8 @@ import { HtmlUtility } from "./html-utility.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js"; import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDUtility } from "./rdd-utility.js"; import { RdDUtility } from "./rdd-utility.js";
import { Grammar } from "./grammar.js"; import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
import {RdDDice } from "./rdd-dice.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
const dossierIconesHeures = 'systems/foundryvtt-reve-de-dragon/icons/heures/' const dossierIconesHeures = 'systems/foundryvtt-reve-de-dragon/icons/heures/'
@ -124,9 +126,9 @@ export class RdDCalendrier extends Application {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
ajouterNombreAstral(index) { async ajouterNombreAstral(index) {
return { return {
nombreAstral: new Roll("1d12").evaluate( {async:false} ).total, nombreAstral: await RdDDice.rollTotal("1dh"),
valeursFausses: [], valeursFausses: [],
index: index index: index
} }
@ -278,11 +280,10 @@ export class RdDCalendrier extends Application {
request.isValid = true; request.isValid = true;
if (!request.rolled.isSuccess) { if (!request.rolled.isSuccess) {
request.isValid = false; request.isValid = false;
let nbAstralFaux = new Roll("1d11").evaluate( { async: false} ).total; nbAstral = await RdDDice.rollTotal("1dhr"+nbAstral);
nbAstral = nbAstral==nbAstralFaux ? 12 : nbAstralFaux;
// Mise à jour des nombres astraux du joueur // Mise à jour des nombres astraux du joueur
let astralData = this.listeNombreAstral.find((nombreAstral, i) => nombreAstral.index == request.date); let astralData = this.listeNombreAstral.find((nombreAstral, i) => nombreAstral.index == request.date);
astralData.valeursFausses.push({ actorId: request.id, nombreAstral: nbAstralFaux }); astralData.valeursFausses.push({ actorId: request.id, nombreAstral: nbAstral });
game.settings.set("foundryvtt-reve-de-dragon", "liste-nombre-astral", this.listeNombreAstral); game.settings.set("foundryvtt-reve-de-dragon", "liste-nombre-astral", this.listeNombreAstral);
} }
request.nbAstral = nbAstral; request.nbAstral = nbAstral;

View File

@ -1,5 +1,6 @@
/* -------------------------------------------- */ /* -------------------------------------------- */
import { DialogCreateSigneDraconique } from "./dialog-create-signedraconique.js";
import { RdDItemCompetence } from "./item-competence.js"; import { RdDItemCompetence } from "./item-competence.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { RdDCarac } from "./rdd-carac.js"; import { RdDCarac } from "./rdd-carac.js";
@ -82,6 +83,17 @@ export class RdDCommands {
descr: `Affiche les heures de chance et de malchance selon l'heure de naissance donnée en argument. Exemples: descr: `Affiche les heures de chance et de malchance selon l'heure de naissance donnée en argument. Exemples:
<br><strong>/astro Lyre</strong>` <br><strong>/astro Lyre</strong>`
}); });
rddCommands.registerCommand({
path: ["/signe", "+"], func: (content, msg, params) => rddCommands.creerSignesDraconiques(),
descr: "Crée un signe draconique et l'ajoute aux haut-rêvants choisis."
});
rddCommands.registerCommand({
path: ["/signe", "-"], func: (content, msg, params) => rddCommands.supprimerSignesDraconiquesEphemeres(),
descr: "Supprime les signes draconiques éphémères"
});
game.system.rdd.commands = rddCommands; game.system.rdd.commands = rddCommands;
} }
} }
@ -271,16 +283,14 @@ export class RdDCommands {
/* -------------------------------------------- */ /* -------------------------------------------- */
async rollDeDraconique(msg) { async rollDeDraconique(msg) {
let ddr = new Roll("1dr + 7").evaluate(); let ddr = await RdDDice.rollTotal("1dr + 7", { showDice:true });
ddr.showDice = true; RdDCommands._chatAnswer(msg, `Lancer d'un Dé draconique: ${ddr}`);
await RdDDice.showDiceSoNice(ddr);
RdDCommands._chatAnswer(msg, `Lancer d'un Dé draconique: ${ddr.total}`);
} }
getTMRAleatoire(msg, params) { async getTMRAleatoire(msg, params) {
if (params.length < 2) { if (params.length < 2) {
let type = params[0]; let type = params[0];
const tmr = TMRUtility.getTMRAleatoire(type ? (it => it.type == type) : (it => true)); const tmr = await TMRUtility.getTMRAleatoire(type ? (it => it.type == type) : (it => true));
RdDCommands._chatAnswer(msg, `Case aléatoire: ${tmr.coord} - ${tmr.label}`); RdDCommands._chatAnswer(msg, `Case aléatoire: ${tmr.coord} - ${tmr.label}`);
} }
else { else {
@ -312,5 +322,20 @@ export class RdDCommands {
} }
} }
async creerSignesDraconiques() {
DialogCreateSigneDraconique.createSigneForActors();
return true;
}
async supprimerSignesDraconiquesEphemeres() {
game.actors.forEach(actor => {
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);
}
});
return true;
}
} }

View File

@ -36,7 +36,7 @@ export class De7 extends Die {
super(termData); super(termData);
} }
evaluate() { async evaluate() {
super.evaluate(); super.evaluate();
this.explode("x=8"); this.explode("x=8");
return this; return this;
@ -73,7 +73,7 @@ export class DeDraconique extends Die {
super(termData); super(termData);
} }
evaluate() { async evaluate() {
super.evaluate(); super.evaluate();
this.explode("x=7"); this.explode("x=7");
return this; return this;
@ -124,6 +124,27 @@ export class RdDDice {
CONFIG.Dice.terms[DeHeure.DENOMINATION] = DeHeure; CONFIG.Dice.terms[DeHeure.DENOMINATION] = DeHeure;
} }
static async roll(formula, options = { showDice: false }) {
const roll = new Roll(formula);
await roll.evaluate({ async: true });
if (options.showDice) {
roll.showDice = options.showDice;
}
await RdDDice.show(roll, game.settings.get("core", "rollMode"));
return roll;
}
static async rollTotal(formula) {
const roll = new Roll(formula);
await roll.evaluate({ async: true });
return roll.total;
}
static async rollOneOf(array) {
const roll = await RdDDice.rollTotal(`1d${array.length}`);
return array[roll-1];
}
static diceSoNiceReady(dice3d) { static diceSoNiceReady(dice3d) {
for (const system of Object.keys(dice3d.DiceFactory.systems)) { for (const system of Object.keys(dice3d.DiceFactory.systems)) {
dice3d.addDicePreset(De7.diceSoNiceData(system)); dice3d.addDicePreset(De7.diceSoNiceData(system));

View File

@ -31,6 +31,7 @@ import { EffetsDraconiques } from "./tmr/effets-draconiques.js";
import { RdDHerbes } from "./rdd-herbes.js"; import { RdDHerbes } from "./rdd-herbes.js";
import { RdDItem } from "./item.js"; import { RdDItem } from "./item.js";
import { RdDDice } from "./rdd-dice.js"; import { RdDDice } from "./rdd-dice.js";
import { RdDSigneDraconiqueItemSheet } from "./item-signedraconique-sheet.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
/* Foundry VTT Initialization */ /* Foundry VTT Initialization */
@ -167,6 +168,11 @@ Hooks.once("init", async function () {
Actors.registerSheet("foundryvtt-reve-de-dragon", RdDActorVehiculeSheet, { types: ["vehicule"], makeDefault: true }); Actors.registerSheet("foundryvtt-reve-de-dragon", RdDActorVehiculeSheet, { types: ["vehicule"], makeDefault: true });
Actors.registerSheet("foundryvtt-reve-de-dragon", RdDActorEntiteSheet, { types: ["entite"], makeDefault: true }); Actors.registerSheet("foundryvtt-reve-de-dragon", RdDActorEntiteSheet, { types: ["entite"], makeDefault: true });
Items.unregisterSheet("core", ItemSheet); Items.unregisterSheet("core", ItemSheet);
Items.registerSheet("foundryvtt-reve-de-dragon", RdDSigneDraconiqueItemSheet, {
label: "Signe draconique",
types: ["signedraconique"],
makeDefault: true
});
Items.registerSheet("foundryvtt-reve-de-dragon", RdDItemSheet, { makeDefault: true }); Items.registerSheet("foundryvtt-reve-de-dragon", RdDItemSheet, { makeDefault: true });
CONFIG.Combat.documentClass = RdDCombatManager; CONFIG.Combat.documentClass = RdDCombatManager;
@ -176,7 +182,7 @@ Hooks.once("init", async function () {
RdDDice.init(); RdDDice.init();
RdDCommands.init(); RdDCommands.init();
RdDCombat.init(); RdDCombat.init();
RdDCombatManager.init(), RdDCombatManager.init();
RdDTokenHud.init(); RdDTokenHud.init();
RdDActor.init(); RdDActor.init();
RddCompendiumOrganiser.init(); RddCompendiumOrganiser.init();

View File

@ -1,14 +1,17 @@
import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { RdDDice } from "./rdd-dice.js";
const words = [ 'pore', 'pre', 'flor', 'lane', 'turlu', 'pin', 'a', 'alph', 'i', 'onse', 'iane', 'ane', 'zach', 'arri', 'ba', 'bo', 'bi', const words = [ 'pore', 'pre', 'flor', 'lane', 'turlu', 'pin', 'a', 'alph', 'i', 'onse', 'iane', 'ane', 'zach', 'arri', 'ba', 'bo', 'bi',
'alta', 'par', 'pir', 'zor', 'zir', 'de', 'pol', 'tran', 'no', 'la','al' , 'pul', 'one', 'ner', 'nur' ]; 'alta', 'par', 'pir', 'zor', 'zir', 'de', 'pol', 'tran', 'no', 'la', 'al' , 'pul', 'one', 'ner', 'nur', 'mac', 'mery',
'cat', 'do', 'di', 'der', 'er', 'el', 'far', 'fer', 'go', 'guer', 'hot', 'jor', 'jar', 'ji', 'kri', 'ket', 'lor', 'hur',
'lar', 'lir', 'lu', 'pot', 'pro', 'pra', 'pit', 'qua', 'qui', 're', 'ral', 'sal', 'sen', 'ted', 'to', 'ta', 'lars', 'ver',
'vin', 'ov', 'wal', 'ry', 'ly', '' ];
/* -------------------------------------------- */ /* -------------------------------------------- */
export class RdDNameGen { export class RdDNameGen {
static getName( msg, params ) { static async getName( msg, params ) {
let name = Misc.upperFirst( Misc.rollOneOf(words) + Misc.rollOneOf(words) ) let name = Misc.upperFirst( await RdDDice.rollOneOf(words) + await RdDDice.rollOneOf(words) )
//console.log(name); //console.log(name);
ChatMessage.create( { content: `Nom : ${name}`, whisper: ChatMessage.getWhisperRecipients("GM") } ); ChatMessage.create( { content: `Nom : ${name}`, whisper: ChatMessage.getWhisperRecipients("GM") } );
} }

View File

@ -149,10 +149,7 @@ export class RdDResolutionTable {
/* -------------------------------------------- */ /* -------------------------------------------- */
static async rollChances(chances, diviseur) { static async rollChances(chances, diviseur) {
let myRoll = new Roll("1d100").evaluate( {async: false} ); chances.roll = await RdDDice.rollTotal("1d100", {showDice:chances.showDice});
myRoll.showDice = chances.showDice;
await RdDDice.show(myRoll);
chances.roll = myRoll.total;
mergeObject(chances, this.computeReussite(chances, chances.roll, diviseur), { overwrite: true }); mergeObject(chances, this.computeReussite(chances, chances.roll, diviseur), { overwrite: true });
return chances; return chances;
} }

View File

@ -205,6 +205,11 @@ export class RdDRoll extends Dialog {
this.updateRollResult(); this.updateRollResult();
$("#diffLibre").val(this.rollData.diffLibre); $("#diffLibre").val(this.rollData.diffLibre);
}); });
html.find('.roll-signedraconique').change((event) => {
let sortKey = Misc.toInt(event.currentTarget.value);
this.setSelectedSigneDraconique(this.rollData.signes[sortKey]);
this.updateRollResult();
});
html.find('#ptreve-variable').change((event) => { html.find('#ptreve-variable').change((event) => {
let ptreve = Misc.toInt(event.currentTarget.value); let ptreve = Misc.toInt(event.currentTarget.value);
this.rollData.selectedSort.data.ptreve_reel = ptreve; this.rollData.selectedSort.data.ptreve_reel = ptreve;
@ -276,6 +281,12 @@ export class RdDRoll extends Dialog {
HtmlUtility._showControlWhen($(".div-sort-ptreve-fixe"), !coutVariable); HtmlUtility._showControlWhen($(".div-sort-ptreve-fixe"), !coutVariable);
} }
async setSelectedSigneDraconique(signe){
this.rollData.signe = signe;
this.rollData.diffLibre = Misc.data(signe).data.difficulte,
$(".signe-difficulte").text(Misc.toSignedString(this.rollData.diffLibre));
}
/* -------------------------------------------- */ /* -------------------------------------------- */
async updateRollResult() { async updateRollResult() {
let rollData = this.rollData; let rollData = this.rollData;

View File

@ -8,31 +8,20 @@ export class RdDRollTables {
const table = await pack.getDocument(entry._id); const table = await pack.getDocument(entry._id);
const draw = await table.draw({ displayChat: toChat, rollMode: "gmroll"}); const draw = await table.draw({ displayChat: toChat, rollMode: "gmroll"});
console.log("RdDRollTables", tableName, toChat, ":", draw); console.log("RdDRollTables", tableName, toChat, ":", draw);
return draw; return draw.results.length > 0 ? draw.results[0] : undefined;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async drawItemFromRollTable(tableName, toChat) { static async drawItemFromRollTable(tableName, toChat = false) {
const draw = await RdDRollTables.genericGetTableResult(tableName, toChat); const drawResult = await RdDRollTables.genericGetTableResult(tableName, toChat);
const drawnItemRef = draw.results.length > 0 ? draw.results[0] : undefined; const pack = game.packs.get(drawResult.data.collection);
if (drawnItemRef.data.collection) { return await pack.getDocument(drawResult.data.resultId);
console.log(drawnItemRef);
const pack = game.packs.get(drawnItemRef.data.collection);
return await pack.getDocument(drawnItemRef.data.resultId);
}
ui.notifications.warn("le tirage ne correspond pas à une entrée d'un Compendium")
return drawnItemRef.text;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async drawTextFromRollTable(tableName, toChat) { static async drawTextFromRollTable(tableName, toChat) {
const draw = await RdDRollTables.genericGetTableResult(tableName, toChat); const drawResult = await RdDRollTables.genericGetTableResult(tableName, toChat);
const drawnItemRef = draw.results.length > 0 ? draw.results[0] : undefined; return drawResult.data.text;
if (drawnItemRef.collection) {
ui.notifications.warn("le tirage correspond à une entrée d'un Compendium, on attendait un texte")
return await pack.getDocument(drawnItemRef.resultId);
}
return drawnItemRef.text;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */

View File

@ -13,6 +13,7 @@ import { Draconique } from "./tmr/draconique.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { HtmlUtility } from "./html-utility.js"; import { HtmlUtility } from "./html-utility.js";
import { ReglesOptionelles } from "./regles-optionelles.js"; import { ReglesOptionelles } from "./regles-optionelles.js";
import { RdDDice } from "./rdd-dice.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
export class RdDTMRDialog extends Dialog { export class RdDTMRDialog extends Dialog {
@ -142,20 +143,27 @@ export class RdDTMRDialog extends Dialog {
_tokenSortEnReserve(sortEnReserve) { _tokenSortEnReserve(sortEnReserve) {
return EffetsDraconiques.sortReserve.token(this.pixiTMR, sortEnReserve.sort, () => sortEnReserve.coord); return EffetsDraconiques.sortReserve.token(this.pixiTMR, sortEnReserve.sort, () => sortEnReserve.coord);
} }
_tokenDemiReve() { _tokenDemiReve() {
const actorData = Misc.data(this.actor); const actorData = Misc.data(this.actor);
return EffetsDraconiques.demiReve.token(this.pixiTMR, actorData, () => actorData.data.reve.tmrpos.coord); return EffetsDraconiques.demiReve.token(this.pixiTMR, actorData, () => actorData.data.reve.tmrpos.coord);
} }
_updateDemiReve() { _updateDemiReve() {
this.notifierResonanceSigneDraconique(this._getActorCoord());
if (!this.cacheTMR) { if (!this.cacheTMR) {
this._setTokenPosition(this.demiReve); this._setTokenPosition(this.demiReve);
} }
} }
_getActorCoord() {
return Misc.data(this.actor).data.reve.tmrpos.coord;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
async moveFromKey(move) { async moveFromKey(move) {
let pos = TMRUtility.convertToCellPos(Misc.data(this.actor).data.reve.tmrpos.coord); let pos = TMRUtility.convertToCellPos(this._getActorCoord());
if (move == 'top') pos.y -= 1; if (move == 'top') pos.y -= 1;
if (move == 'bottom') pos.y += 1; if (move == 'bottom') pos.y += 1;
@ -178,22 +186,25 @@ export class RdDTMRDialog extends Dialog {
async activateListeners(html) { async activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
HtmlUtility._showControlWhen($(".appliquerFatigue"), ReglesOptionelles.isUsing("appliquer-fatigue"));
document.getElementById("tmrrow1").insertCell(0).append(this.pixiApp.view); document.getElementById("tmrrow1").insertCell(0).append(this.pixiApp.view);
if (this.viewOnly) { if (this.viewOnly) {
html.find('#lancer-sort').remove(); html.find('.lancer-sort').remove();
} html.find('.lire-signe-draconique').remove();
else {
// Roll Sort
html.find('#lancer-sort').click((event) => {
this.actor.rollUnSort(Misc.data(this.actor).data.reve.tmrpos.coord);
});
}
if (this.viewOnly) {
return; return;
} }
HtmlUtility._showControlWhen($(".appliquerFatigue"), ReglesOptionelles.isUsing("appliquer-fatigue"));
HtmlUtility._showControlWhen($(".lire-signe-draconique"), this.actor.isResonanceSigneDraconique(this._getActorCoord()));
// Roll Sort
html.find('.lancer-sort').click((event) => {
this.actor.rollUnSort(this._getActorCoord());
});
html.find('.lire-signe-draconique').click((event) => {
this.actor.rollLireSigneDraconique(this._getActorCoord());
});
html.find('#dir-top').click((event) => { html.find('#dir-top').click((event) => {
this.moveFromKey("top"); this.moveFromKey("top");
}); });
@ -213,7 +224,6 @@ export class RdDTMRDialog extends Dialog {
this.moveFromKey("bottom"); this.moveFromKey("bottom");
}); });
// Gestion du cout de montée en points de rêve // Gestion du cout de montée en points de rêve
let reveCout = ((this.tmrdata.isRapide && !EffetsDraconiques.isDeplacementAccelere(this.actor)) ? -2 : -1) - this.actor.countMonteeLaborieuse(); let reveCout = ((this.tmrdata.isRapide && !EffetsDraconiques.isDeplacementAccelere(this.actor)) ? -2 : -1) - this.actor.countMonteeLaborieuse();
if (ReglesOptionelles.isUsing("appliquer-fatigue")) { if (ReglesOptionelles.isUsing("appliquer-fatigue")) {
@ -223,24 +233,27 @@ export class RdDTMRDialog extends Dialog {
// Le reste... // Le reste...
this.updateValuesDisplay(); this.updateValuesDisplay();
let tmr = TMRUtility.getTMR(Misc.data(this.actor).data.reve.tmrpos.coord); let tmr = TMRUtility.getTMR(this._getActorCoord());
await this.manageRencontre(tmr, () => { await this.manageRencontre(tmr, () => {
this.postRencontre(tmr); this.postRencontre(tmr);
}); });
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
updateValuesDisplay() { async updateValuesDisplay() {
let ptsreve = document.getElementById("tmr-pointsreve-value"); const coord = this._getActorCoord();
const actorData = Misc.data(this.actor); const actorData = Misc.data(this.actor);
HtmlUtility._showControlWhen($(".lire-signe-draconique"), this.actor.isResonanceSigneDraconique(coord));
let ptsreve = document.getElementById("tmr-pointsreve-value");
ptsreve.innerHTML = actorData.data.reve.reve.value; ptsreve.innerHTML = actorData.data.reve.reve.value;
let tmrpos = document.getElementById("tmr-pos"); let tmrpos = document.getElementById("tmr-pos");
if (this.cacheTMR) { if (this.cacheTMR) {
tmrpos.innerHTML = '?? ('+ TMRUtility.getTMRType( actorData.data.reve.tmrpos.coord ) + ')'; tmrpos.innerHTML = '?? (' + TMRUtility.getTMRType(coord) + ')';
} else { } else {
let tmr = TMRUtility.getTMR(actorData.data.reve.tmrpos.coord); tmrpos.innerHTML = coord + " (" + TMRUtility.getTMRLabel(coord) + ")";
tmrpos.innerHTML = actorData.data.reve.tmrpos.coord + " (" + tmr.label + ")";
} }
let etat = document.getElementById("tmr-etatgeneral-value"); let etat = document.getElementById("tmr-etatgeneral-value");
@ -373,7 +386,7 @@ export class RdDTMRDialog extends Dialog {
rencontre: this.currentRencontre, rencontre: this.currentRencontre,
nbRounds: 1, nbRounds: 1,
canClose: false, canClose: false,
tmr: TMRUtility.getTMR(Misc.data(this.actor).data.reve.tmrpos.coord) tmr: TMRUtility.getTMR(this._getActorCoord())
} }
await this._tentativeMaitrise(rencontreData); await this._tentativeMaitrise(rencontreData);
@ -523,7 +536,7 @@ export class RdDTMRDialog extends Dialog {
if (rencontre) { if (rencontre) {
return rencontre; return rencontre;
} }
let myRoll = new Roll("1d7").evaluate( { async: false} ).total; let myRoll = await RdDDice.rollTotal("1d7");
if (TMRUtility.isForceRencontre() || myRoll == 7) { if (TMRUtility.isForceRencontre() || myRoll == 7) {
return await this.rencontreTMRRoll(tmr, this.actor.isRencontreSpeciale()); return await this.rencontreTMRRoll(tmr, this.actor.isRencontreSpeciale());
} }
@ -584,7 +597,7 @@ export class RdDTMRDialog extends Dialog {
await this._rollMaitriseCaseHumide(rollData); await this._rollMaitriseCaseHumide(rollData);
return; return;
} }
rollData.poesie = Poetique.getExtrait(); rollData.poesie = await Poetique.getExtrait();
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name), whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-maitrise-tmr.html`, rollData) content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-maitrise-tmr.html`, rollData)
@ -701,7 +714,7 @@ export class RdDTMRDialog extends Dialog {
} }
this.toclose = rollData.rolled.isEchec; this.toclose = rollData.rolled.isEchec;
rollData.poesie = Poetique.getExtrait(); rollData.poesie = await Poetique.getExtrait();
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name), whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-maitrise-tmr.html`, rollData) content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-maitrise-tmr.html`, rollData)
@ -852,7 +865,7 @@ export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
async _onClickTMRPos(eventPos) { async _onClickTMRPos(eventPos) {
let currentPos = TMRUtility.convertToCellPos(Misc.data(this.actor).data.reve.tmrpos.coord); let currentPos = TMRUtility.convertToCellPos(this._getActorCoord());
console.log("deplacerDemiReve >>>>", currentPos, eventPos); console.log("deplacerDemiReve >>>>", currentPos, eventPos);
@ -896,6 +909,7 @@ export class RdDTMRDialog extends Dialog {
Si la case est le demi-rêve, ne pas lancer de sort. Si la case est le demi-rêve, ne pas lancer de sort.
Si un lancement de sort est en cours, trouver un moyen de réafficher cette fenêtre si on essaie de lancer un sort (ou bloquer le lancer de sort) Si un lancement de sort est en cours, trouver un moyen de réafficher cette fenêtre si on essaie de lancer un sort (ou bloquer le lancer de sort)
*/ */
this.notifierResonanceSigneDraconique(targetCoord);
await this.actor.rollUnSort(targetCoord); await this.actor.rollUnSort(targetCoord);
this.nettoyerRencontre(); this.nettoyerRencontre();
} }
@ -920,7 +934,6 @@ export class RdDTMRDialog extends Dialog {
// Gestion cases spéciales type Trou noir, etc // Gestion cases spéciales type Trou noir, etc
tmr = await this.manageTmrInnaccessible(tmr); tmr = await this.manageTmrInnaccessible(tmr);
this.actor.updateCoordTMR(tmr.coord);
await this.actor.updateCoordTMR(tmr.coord); await this.actor.updateCoordTMR(tmr.coord);
this._updateDemiReve(); this._updateDemiReve();
@ -943,6 +956,15 @@ export class RdDTMRDialog extends Dialog {
} }
} }
async notifierResonanceSigneDraconique(coord) {
if (this.actor.isResonanceSigneDraconique(coord)) {
ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-signe-draconique-resonance.html`, { alias: this.actor.name, typeTMR: TMRUtility.getTMRType(coord) })
});
}
}
/* -------------------------------------------- */ /* -------------------------------------------- */
async postRencontre(tmr) { async postRencontre(tmr) {
if (!(this.viewOnly || this.currentRencontre)) { if (!(this.viewOnly || this.currentRencontre)) {

View File

@ -7,6 +7,7 @@ import { Grammar } from "./grammar.js";
import { TMRUtility } from "./tmr-utility.js"; import { TMRUtility } from "./tmr-utility.js";
import { DialogItemAchat } from "./dialog-item-achat.js"; import { DialogItemAchat } from "./dialog-item-achat.js";
import { ReglesOptionelles } from "./regles-optionelles.js"; import { ReglesOptionelles } from "./regles-optionelles.js";
import { RdDDice } from "./rdd-dice.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
// This table starts at 0 -> niveau -10 // This table starts at 0 -> niveau -10
@ -140,6 +141,7 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/item-monnaie-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/item-monnaie-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/item-meditation-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/item-meditation-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/item-nourritureboisson-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/item-nourritureboisson-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/item-signedraconique-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/competence-carac-defaut.html', 'systems/foundryvtt-reve-de-dragon/templates/competence-carac-defaut.html',
'systems/foundryvtt-reve-de-dragon/templates/competence-base.html', 'systems/foundryvtt-reve-de-dragon/templates/competence-base.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-aspect-tarot.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-aspect-tarot.html',
@ -204,7 +206,8 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/chat-actor-competence-xp.html', 'systems/foundryvtt-reve-de-dragon/templates/chat-actor-competence-xp.html',
'systems/foundryvtt-reve-de-dragon/templates/chat-actor-carac-xp.html', 'systems/foundryvtt-reve-de-dragon/templates/chat-actor-carac-xp.html',
'systems/foundryvtt-reve-de-dragon/templates/chat-potionenchantee-chateaudormant.html', 'systems/foundryvtt-reve-de-dragon/templates/chat-potionenchantee-chateaudormant.html',
'systems/foundryvtt-reve-de-dragon/templates/chat-fabriquer-potion-base.html' 'systems/foundryvtt-reve-de-dragon/templates/chat-fabriquer-potion-base.html',
'systems/foundryvtt-reve-de-dragon/templates/chat-signe-draconique-actor.html'
]; ];
Handlebars.registerHelper('upperFirst', str => Misc.upperFirst(str ?? 'Null')); Handlebars.registerHelper('upperFirst', str => Misc.upperFirst(str ?? 'Null'));
@ -271,6 +274,7 @@ export class RdDUtility {
formData.munitions = this.checkNull(formData.itemsByType['munition']); formData.munitions = this.checkNull(formData.itemsByType['munition']);
formData.herbes = this.checkNull(formData.itemsByType['herbe']); formData.herbes = this.checkNull(formData.itemsByType['herbe']);
formData.sorts = this.checkNull(formData.itemsByType['sort']); formData.sorts = this.checkNull(formData.itemsByType['sort']);
formData.signesdraconiques = this.checkNull(formData.itemsByType['signedraconique']);
formData.queues = this.checkNull(formData.itemsByType['queue']); formData.queues = this.checkNull(formData.itemsByType['queue']);
formData.souffles = this.checkNull(formData.itemsByType['souffle']); formData.souffles = this.checkNull(formData.itemsByType['souffle']);
formData.ombres = this.checkNull(formData.itemsByType['ombre']); formData.ombres = this.checkNull(formData.itemsByType['ombre']);
@ -441,8 +445,8 @@ export class RdDUtility {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static getLocalisation(type = 'personnage') { static async getLocalisation(type = 'personnage') {
let result = new Roll("1d20").roll().total; let result = await RdDDice.rollTotal("1d20");
let txt = "" let txt = ""
if (type == 'personnage') { if (type == 'personnage') {
if (result <= 3) txt = "Jambe, genou, pied, jarret"; if (result <= 3) txt = "Jambe, genou, pied, jarret";
@ -474,15 +478,6 @@ export class RdDUtility {
return duplicate(table[0]); return duplicate(table[0]);
} }
/* -------------------------------------------- */
static _evaluatePerte(formula, over20) {
console.log("_evaluatePerte", formula, over20);
let perte = new Roll(formula, { over20: over20 });
perte.evaluate();
return perte.total;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static currentFatigueMalus(value, max) { static currentFatigueMalus(value, max) {
if (ReglesOptionelles.isUsing("appliquer-fatigue")) { if (ReglesOptionelles.isUsing("appliquer-fatigue")) {

View File

@ -1,5 +1,6 @@
import { Grammar } from "./grammar.js"; import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { RdDDice } from "./rdd-dice.js";
import { TMRUtility } from "./tmr-utility.js"; import { TMRUtility } from "./tmr-utility.js";
import { TMRType } from "./tmr-utility.js"; import { TMRType } from "./tmr-utility.js";
@ -268,7 +269,7 @@ const rencontresStandard = [
{ code: "reflet", name: "Reflet d'ancien Rêve", type: "reflet", genre: "m", force: "2d6", isPersistant: true }, { code: "reflet", name: "Reflet d'ancien Rêve", type: "reflet", genre: "m", force: "2d6", isPersistant: true },
{ code: "tbblanc", name: "Tourbillon blanc", type: "tbblanc", genre: "m", force: "2d6", isPersistant: true }, { code: "tbblanc", name: "Tourbillon blanc", type: "tbblanc", genre: "m", force: "2d6", isPersistant: true },
{ code: "tbnoir", name: "Tourbillon noir", type: "tbnoir", genre: "m", force: "2d8", isPersistant: true }, { code: "tbnoir", name: "Tourbillon noir", type: "tbnoir", genre: "m", force: "2d8", isPersistant: true },
{ code: "rdd", name: "Rêve de Dragon", type: "rdd", genre: "m", force: "1ddr + 7", refoulement: 2, quitterTMR: true } { code: "rdd", name: "Rêve de Dragon", type: "rdd", genre: "m", force: "1dr + 7", refoulement: 2, quitterTMR: true }
]; ];
const rencontresPresentCite = [ const rencontresPresentCite = [
@ -324,7 +325,7 @@ export class TMRRencontres {
return false; return false;
} }
if (!roll || roll <= 0 || roll > 100) { if (!roll || roll <= 0 || roll > 100) {
roll = new Roll("1d100").evaluate().total; roll = await RdDDice.rollTotal("1d100");
} }
let rencontre = await TMRRencontres.getRencontreAleatoire(terrain, roll); let rencontre = await TMRRencontres.getRencontreAleatoire(terrain, roll);
ChatMessage.create({ ChatMessage.create({
@ -356,15 +357,13 @@ export class TMRRencontres {
/* -------------------------------------------- */ /* -------------------------------------------- */
static async getRencontreAleatoire(terrain, roll = undefined) { static async getRencontreAleatoire(terrain, roll = undefined) {
if (!roll || roll <= 0 || roll > 100) { if (!roll || roll <= 0 || roll > 100) {
roll = new Roll("1d100").evaluate({ async: false }).total; roll = await RdDDice.rollTotal("1d100");
} }
terrain = Grammar.toLowerCaseNoAccent(terrain); terrain = Grammar.toLowerCaseNoAccent(terrain);
//console.log("getRencontreAleatoire", terrain, roll);
const code = tableRencontres[terrain].find(it => it.range[0] <= roll && roll <= it.range[1]).code; const code = tableRencontres[terrain].find(it => it.range[0] <= roll && roll <= it.range[1]).code;
const rencontre = duplicate(rencontresStandard.find(it => it.code == code)); const rencontre = duplicate(rencontresStandard.find(it => it.code == code));
rencontre.roll = roll; rencontre.roll = roll;
await TMRRencontres.evaluerForceRencontre(rencontre); await TMRRencontres.evaluerForceRencontre(rencontre);
//console.log(rencontre);
return rencontre; return rencontre;
} }
@ -373,20 +372,14 @@ export class TMRRencontres {
const rencontre = duplicate( const rencontre = duplicate(
(index && index >= 0 && index < mauvaisesRencontres.length) (index && index >= 0 && index < mauvaisesRencontres.length)
? mauvaisesRencontres[index] ? mauvaisesRencontres[index]
: Misc.rollOneOf(mauvaisesRencontres)); : await RdDDice.rollOneOf(mauvaisesRencontres));
await TMRRencontres.evaluerForceRencontre(rencontre); await TMRRencontres.evaluerForceRencontre(rencontre);
return rencontre; return rencontre;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async evaluerForceRencontre(rencontre) { static async evaluerForceRencontre(rencontre) {
if (TMRRencontres.isReveDeDragon(rencontre)) { rencontre.force = await new Roll(rencontre.force).evaluate().total;
const ddr = new Roll("1dr + 7").evaluate();
rencontre.force = 7 + ddr.total;
}
else {
rencontre.force = new Roll(rencontre.force).evaluate({ async: false }).total;
}
return rencontre.force; return rencontre.force;
} }
@ -426,14 +419,14 @@ export class TMRRencontres {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static msgEchecPasseurFou(tmrData) { static async msgEchecPasseurFou(tmrData) {
tmrData.sortReserve = Misc.templateData(tmrData.actor).reve.reserve.list[0]; tmrData.sortReserve = Misc.templateData(tmrData.actor).reve.reserve.list[0];
if (tmrData.sortReserve) { if (tmrData.sortReserve) {
// Passeur fou positionne sur la case d'un ort en réserve // TODO : Choisir le sort le plus loin ou au hasard // Passeur fou positionne sur la case d'un ort en réserve // TODO : Choisir le sort le plus loin ou au hasard
tmrData.newTMR = TMRUtility.getTMR(tmrData.sortReserve.coord); tmrData.newTMR = TMRUtility.getTMR(tmrData.sortReserve.coord);
} else { } else {
// Déplacement aléatoire de la force du Passeur Fou // Déplacement aléatoire de la force du Passeur Fou
const newCoord = Misc.rollOneOf(TMRUtility.getTMRPortee(tmrData.tmr.coord, tmrData.rencontre.force)); const newCoord = await RdDDice.rollOneOf(TMRUtility.getTMRPortee(tmrData.tmr.coord, tmrData.rencontre.force));
tmrData.newTMR = TMRUtility.getTMR(newCoord); tmrData.newTMR = TMRUtility.getTMR(newCoord);
} }
if (tmrData.sortReserve) { if (tmrData.sortReserve) {
@ -472,7 +465,7 @@ export class TMRRencontres {
static async _toubillonner(tmrDialog, actor, cases) { static async _toubillonner(tmrDialog, actor, cases) {
let coord = Misc.templateData(actor).reve.tmrpos.coord; let coord = Misc.templateData(actor).reve.tmrpos.coord;
for (let i = 0; i < cases; i++) { for (let i = 0; i < cases; i++) {
coord = TMRUtility.deplaceTMRAleatoire(actor, coord).coord; coord = await TMRUtility.deplaceTMRAleatoire(actor, coord).coord;
} }
await tmrDialog.forceDemiRevePosition(coord) await tmrDialog.forceDemiRevePosition(coord)
} }

View File

@ -1,6 +1,7 @@
import { TMRRencontres } from "./tmr-rencontres.js"; import { TMRRencontres } from "./tmr-rencontres.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { Grammar } from "./grammar.js"; import { Grammar } from "./grammar.js";
import { RdDDice } from "./rdd-dice.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
const TMRMapping = { const TMRMapping = {
@ -338,7 +339,7 @@ export class TMRUtility {
static getTMRType(coord) { static getTMRType(coord) {
const tmr = TMRMapping[coord]; const tmr = TMRMapping[coord];
return Misc.upperFirst(tmr.type); return Misc.upperFirst(TMRType[tmr.type].name);
} }
static getTMRDescr(coord) { static getTMRDescr(coord) {
@ -346,6 +347,12 @@ export class TMRUtility {
return Grammar.articleDetermine(tmr.type) + ' ' + tmr.label; return Grammar.articleDetermine(tmr.type) + ' ' + tmr.label;
} }
static listSelectedTMR(typesTMR) {
return Object.values(TMRType).map(value => Misc.upperFirst(value.name))
.sort()
.map(name => { return { name: name, selected: typesTMR.includes(name) } });
}
static isCaseHumide(tmr) { static isCaseHumide(tmr) {
return tmr.type == 'fleuve' || tmr.type == 'lac' || tmr.type == 'marais'; return tmr.type == 'fleuve' || tmr.type == 'lac' || tmr.type == 'marais';
} }
@ -380,13 +387,13 @@ export class TMRUtility {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static getDirectionPattern() { static async getDirectionPattern() {
return Misc.rollOneOf(tmrRandomMovePatten); return await RdDDice.rollOneOf(tmrRandomMovePatten);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static deplaceTMRAleatoire(actor, coord) { static async deplaceTMRAleatoire(actor, coord) {
return TMRUtility.deplaceTMRSelonPattern(actor, coord, TMRUtility.getDirectionPattern(), 1); return TMRUtility.deplaceTMRSelonPattern(actor, coord, await TMRUtility.getDirectionPattern(), 1);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -418,8 +425,8 @@ export class TMRUtility {
return TMRUtility.filterTMR(filter).map(it => it.coord); return TMRUtility.filterTMR(filter).map(it => it.coord);
} }
static getTMRAleatoire(filter = it => true) { static async getTMRAleatoire(filter = it => true) {
return Misc.rollOneOf(TMRUtility.filterTMR(filter)) return await RdDDice.rollOneOf(TMRUtility.filterTMR(filter))
} }
/* -------------------------------------------- */ /* -------------------------------------------- */

View File

@ -1,5 +1,6 @@
import { Grammar } from "../grammar.js"; import { Grammar } from "../grammar.js";
import { Misc } from "../misc.js"; import { Misc } from "../misc.js";
import { RdDDice } from "../rdd-dice.js";
import { tmrColors, tmrConstants, tmrTokenZIndex, TMRUtility } from "../tmr-utility.js"; import { tmrColors, tmrConstants, tmrTokenZIndex, TMRUtility } from "../tmr-utility.js";
import { Draconique } from "./draconique.js"; import { Draconique } from "./draconique.js";
@ -31,7 +32,7 @@ export class Conquete extends Draconique {
async _creerConquete(actor, queue) { async _creerConquete(actor, queue) {
let existants = actor.data.items.filter(it => this.isCase(it)).map(it => Misc.data(it).data.coord); let existants = actor.data.items.filter(it => this.isCase(it)).map(it => Misc.data(it).data.coord);
let possibles = TMRUtility.filterTMR(tmr => !TMRUtility.isCaseHumide(tmr) && !existants.includes(tmr.coord)); let possibles = TMRUtility.filterTMR(tmr => !TMRUtility.isCaseHumide(tmr) && !existants.includes(tmr.coord));
let conquete = Misc.rollOneOf(possibles); let conquete =await RdDDice.rollOneOf(possibles);
await this.createCaseTmr(actor, 'Conquête: ' + conquete.label, conquete, queue.id); await this.createCaseTmr(actor, 'Conquête: ' + conquete.label, conquete, queue.id);
} }

View File

@ -13,7 +13,7 @@ export class Debordement extends Draconique {
manualMessage() { return false } manualMessage() { return false }
async onActorCreateOwned(actor, souffle) { async onActorCreateOwned(actor, souffle) {
const existants = actor.data.items.filter(it => this.isCase(it)).map(it => it.data.coord); const existants = actor.data.items.filter(it => this.isCase(it)).map(it => it.data.coord);
const tmr = TMRUtility.getTMRAleatoire(it => !(TMRUtility.isCaseHumide(it) || existants.includes(it.coord))); const tmr = await TMRUtility.getTMRAleatoire(it => !(TMRUtility.isCaseHumide(it) || existants.includes(it.coord)));
await this.createCaseTmr(actor, 'Debordement: ' + tmr.label, tmr, souffle.id); await this.createCaseTmr(actor, 'Debordement: ' + tmr.label, tmr, souffle.id);
} }

View File

@ -1,5 +1,6 @@
import { Grammar } from "../grammar.js"; import { Grammar } from "../grammar.js";
import { Misc } from "../misc.js"; import { Misc } from "../misc.js";
import { RdDDice } from "../rdd-dice.js";
import { tmrColors, tmrConstants, tmrTokenZIndex, TMRType, TMRUtility } from "../tmr-utility.js"; import { tmrColors, tmrConstants, tmrTokenZIndex, TMRType, TMRUtility } from "../tmr-utility.js";
import { Draconique } from "./draconique.js"; import { Draconique } from "./draconique.js";
@ -13,7 +14,7 @@ export class Desorientation extends Draconique {
manualMessage() { return false } manualMessage() { return false }
async onActorCreateOwned(actor, souffle) { async onActorCreateOwned(actor, souffle) {
const type = Misc.rollOneOf(this._typesPossibles(actor)); const type = await RdDDice.rollOneOf(this._typesPossibles(actor));
console.log("désorientation", type); console.log("désorientation", type);
souffle.name += ": " + TMRType[type].name; souffle.name += ": " + TMRType[type].name;
await this._creerCasesTmr(actor, type, souffle); await this._creerCasesTmr(actor, type, souffle);

View File

@ -13,7 +13,7 @@ export class Pelerinage extends Draconique {
manualMessage() { return false } manualMessage() { return false }
async onActorCreateOwned(actor, queue) { async onActorCreateOwned(actor, queue) {
let tmr = TMRUtility.getTMRAleatoire(); let tmr = await TMRUtility.getTMRAleatoire();
await this.createCaseTmr(actor, 'Pèlerinage: ' + tmr.label, tmr, queue.id); await this.createCaseTmr(actor, 'Pèlerinage: ' + tmr.label, tmr, queue.id);
} }

View File

@ -1,5 +1,6 @@
import { Grammar } from "../grammar.js"; import { Grammar } from "../grammar.js";
import { tmrColors, tmrConstants, tmrTokenZIndex, TMRUtility } from "../tmr-utility.js"; import { RdDDice } from "../rdd-dice.js";
import { tmrConstants, tmrTokenZIndex, TMRUtility } from "../tmr-utility.js";
import { Draconique } from "./draconique.js"; import { Draconique } from "./draconique.js";
export class Periple extends Draconique { export class Periple extends Draconique {
@ -13,7 +14,7 @@ export class Periple extends Draconique {
manualMessage() { return false } manualMessage() { return false }
async onActorCreateOwned(actor, souffle) { async onActorCreateOwned(actor, souffle) {
let terrain = new Roll("1d2").evaluate().total == 1 ? 'sanctuaire' : 'necropole'; let terrain = (await RdDDice.rollTotal("1d2")) == 1 ? 'sanctuaire' : 'necropole';
let tmrs = TMRUtility.getListTMR(terrain); let tmrs = TMRUtility.getListTMR(terrain);
for (let tmr of tmrs) { for (let tmr of tmrs) {
await this.createCaseTmr(actor, 'Périple: ' + tmr.label, tmr, souffle.id); await this.createCaseTmr(actor, 'Périple: ' + tmr.label, tmr, souffle.id);

View File

@ -12,7 +12,7 @@ export class ReserveExtensible extends Draconique {
manualMessage() { return "Vous pouvez re-configurer votre Réserve extensible" } manualMessage() { return "Vous pouvez re-configurer votre Réserve extensible" }
async onActorCreateOwned(actor, tete) { async onActorCreateOwned(actor, tete) {
const existants = actor.data.items.filter(it => this.isCase(it)).map(it => it.data.coord); const existants = actor.data.items.filter(it => this.isCase(it)).map(it => it.data.coord);
const tmr = TMRUtility.getTMRAleatoire(it => !(it.type == 'fleuve' || existants.includes(it.coord))); const tmr = await TMRUtility.getTMRAleatoire(it => !(it.type == 'fleuve' || existants.includes(it.coord)));
await this.createCaseTmr(actor, "Nouvelle Réserve extensible", tmr, tete.id); await this.createCaseTmr(actor, "Nouvelle Réserve extensible", tmr, tete.id);
} }

View File

@ -13,7 +13,7 @@ export class TrouNoir extends Draconique {
async onActorCreateOwned(actor, souffle) { async onActorCreateOwned(actor, souffle) {
const existants = actor.data.items.filter(it => this.isCase(it)).map(it => it.data.coord); const existants = actor.data.items.filter(it => this.isCase(it)).map(it => it.data.coord);
const tmr = TMRUtility.getTMRAleatoire(it => !(TMRUtility.isCaseHumide(it) || existants.includes(it.coord))); const tmr = await TMRUtility.getTMRAleatoire(it => !(TMRUtility.isCaseHumide(it) || existants.includes(it.coord)));
await this.createCaseTmr(actor, 'Trou noir: ' + tmr.label, tmr, souffle.id); await this.createCaseTmr(actor, 'Trou noir: ' + tmr.label, tmr, souffle.id);
} }

File diff suppressed because one or more lines are too long

View File

@ -577,7 +577,7 @@
"Item": { "Item": {
"types": ["objet", "arme", "armure", "conteneur", "competence", "sort", "herbe", "ingredient", "livre", "potion", "munition", "rencontresTMR", "queue", "ombre", "souffle", "types": ["objet", "arme", "armure", "conteneur", "competence", "sort", "herbe", "ingredient", "livre", "potion", "munition", "rencontresTMR", "queue", "ombre", "souffle",
"tete", "competencecreature", "tarot", "monnaie", "nombreastral", "tache", "meditation", "casetmr", "recettealchimique", "tete", "competencecreature", "tarot", "monnaie", "nombreastral", "tache", "meditation", "casetmr", "recettealchimique",
"musique", "chant", "danse", "jeu", "recettecuisine", "maladie", "poison", "oeuvre", "nourritureboisson" ], "musique", "chant", "danse", "jeu", "recettecuisine", "maladie", "poison", "oeuvre", "nourritureboisson", "signedraconique" ],
"objet": { "objet": {
"description": "", "description": "",
"quantite": 1, "quantite": 1,
@ -868,6 +868,18 @@
"encombrement": 0, "encombrement": 0,
"quantite": 1, "quantite": 1,
"cout": 0 "cout": 0
},
"signedraconique": {
"typesTMR": [],
"ephemere": true,
"duree": "1 round",
"difficulte": 0,
"valeur": {
"norm": 3,
"sign": 5,
"part": 10
},
"description": ""
} }
} }
} }

View File

@ -310,7 +310,7 @@
<ul class="item-list alterne-list"> <ul class="item-list alterne-list">
{{#each taches as |tache id|}} {{#each taches as |tache id|}}
<li class="item flexrow list-item" data-item-id="{{tache._id}}"><span class="competence-title tache-label"><a>{{tache.name}} ({{tache.data.points_de_tache_courant}}/{{tache.data.points_de_tache}})</a></span> <li class="item flexrow list-item" data-item-id="{{tache._id}}"><span class="competence-title tache-label"><a>{{tache.name}} ({{tache.data.points_de_tache_courant}}/{{tache.data.points_de_tache}})</a></span>
<div class="item-controls"> <div class="item-controls flex-shrink">
<a class="item-control item-edit" title="Edit Item"><i class="fas fa-edit"></i></a> <a class="item-control item-edit" title="Edit Item"><i class="fas fa-edit"></i></a>
<a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a> <a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
</div> </div>
@ -340,7 +340,7 @@
<ul class="item-list alterne-list"> <ul class="item-list alterne-list">
{{#each jeux as |jeu id|}} {{#each jeux as |jeu id|}}
<li class="item flexrow list-item" data-item-id="{{jeu._id}}"><span class="competence-title jeu-label"><a>{{jeu.name}} (base {{jeu.data.base}})</a></span> <li class="item flexrow list-item" data-item-id="{{jeu._id}}"><span class="competence-title jeu-label"><a>{{jeu.name}} (base {{jeu.data.base}})</a></span>
<div class="item-controls"> <div class="item-controls flex-shrink">
<a class="item-control item-edit" title="Edit Item"><i class="fas fa-edit"></i></a> <a class="item-control item-edit" title="Edit Item"><i class="fas fa-edit"></i></a>
<a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a> <a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
</div> </div>
@ -351,7 +351,7 @@
<ul class="item-list alterne-list"> <ul class="item-list alterne-list">
{{#each recettesAlchimiques as |recette id|}} {{#each recettesAlchimiques as |recette id|}}
<li class="item flexrow list-item" data-item-id="{{recette._id}}"><span class="competence-title recette-label item-edit"><a>{{recette.name}}</a></span> <li class="item flexrow list-item" data-item-id="{{recette._id}}"><span class="competence-title recette-label item-edit"><a>{{recette.name}}</a></span>
<div class="item-controls"> <div class="item-controls flex-shrink">
<a class="item-control item-edit" title="Edit Item"><i class="fas fa-edit"></i></a> <a class="item-control item-edit" title="Edit Item"><i class="fas fa-edit"></i></a>
<a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a> <a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
</div> </div>
@ -384,20 +384,28 @@
</li> </li>
{{/if}} {{/if}}
<li class="item flexrow"> <li class="item flexrow">
<span class="competence-label">Demi rêve :</span>
<span>
{{#if options.isGM}} {{#if options.isGM}}
{{caseTmr-label data.reve.tmrpos.coord}} <span class="competence-label flex-shrink">Demi rêve :
<span>{{caseTmr-label data.reve.tmrpos.coord}}</span>
</span>
<span>
<input class="competence-value" type="text" name="data.reve.tmrpos.coord" value="{{data.reve.tmrpos.coord}}" data-dtype="String"/> <input class="competence-value" type="text" name="data.reve.tmrpos.coord" value="{{data.reve.tmrpos.coord}}" data-dtype="String"/>
</span>
{{else}} {{else}}
<span class="competence-label flex-shrink">Demi rêve :
{{#unless hautreve.cacheTMR}}
<span>{{caseTmr-label data.reve.tmrpos.coord}}</span>
{{/unless}}
</span>
<span>
{{#if hautreve.cacheTMR}} {{#if hautreve.cacheTMR}}
?? ??
{{else}} {{else}}
{{caseTmr-label data.reve.tmrpos.coord}}
{{data.reve.tmrpos.coord}} {{data.reve.tmrpos.coord}}
{{/if}} {{/if}}
{{/if}}
</span> </span>
{{/if}}
</li> </li>
{{/if}} {{/if}}
<li class="item flexrow"> <li class="item flexrow">
@ -424,13 +432,27 @@
</div> </div>
<hr> <hr>
{{#if data.attributs.hautrevant.value}} {{#if data.attributs.hautrevant.value}}
{{#if options.isGM}}
<h3>Signes draconiques</h3>
<ul class="item-list alterne-list">
{{#each signesdraconiques as |signe key|}}
<li class="item list-item flexrow" data-item-id="{{signe._id}}" data-attribute="{{key}}">
<span class="display-label flex-grow"> <a data-item-id="{{signe._id}}">{{signe.name}}</a></span>
<span class="flex-shrink">{{signe.data.difficulte}}</span>
<div class="item-controls flex-shrink">
<a class="item-control item-delete" title="Supprimer"><i class="fas fa-trash"></i></a>
</div>
</li>
{{/each}}
</ul>
{{/if}}
<h3>Sorts:</h3> <h3>Sorts:</h3>
<ul class="item-list alterne-list"> <ul class="item-list alterne-list">
{{#each sorts as |mysort key|}} {{#each sorts as |sort key|}}
<li class="item list-item flexrow" data-item-id="{{mysort._id}}" data-attribute="{{key}}"> <li class="item list-item flexrow" data-item-id="{{sort._id}}" data-attribute="{{key}}">
<span class="sort-label"> <a data-id="{{mysort._id}}">{{mysort.name}}</a></span> <span class="display-label flex-grow"> <a data-item-id="{{sort._id}}">{{sort.name}}</a></span>
<span>{{mysort.data.draconic}} / {{mysort.data.difficulte}}</span> <span>{{sort.data.draconic}} / {{sort.data.difficulte}}</span>
<div class="item-controls"> <div class="item-controls flex-shrink">
<a class="item-control item-delete" title="Supprimer"><i class="fas fa-trash"></i></a> <a class="item-control item-delete" title="Supprimer"><i class="fas fa-trash"></i></a>
</div> </div>
</li> </li>
@ -440,9 +462,15 @@
<h3>Sorts en Réserve:</h3> <h3>Sorts en Réserve:</h3>
<ul class="item-list alterne-list"> <ul class="item-list alterne-list">
{{#each hautreve.sortsReserve as |reserve key|}} {{#each hautreve.sortsReserve as |reserve key|}}
<li class="item list-item flexrow" data-item-id="{{mysort._id}}" data-attribute="{{key}}"> <li class="item list-item flexrow" data-item-id="{{reserve._id}}" data-attribute="{{key}}">
<img class="sheet-competence-img" src="{{reserve.sort.img}}" /> <img class="sheet-competence-img" src="{{reserve.sort.img}}" />
<span class="sort-label"> {{reserve.sort.name}} - {{reserve.coord}} - {{caseTmr-label reserve.coord}} - r{{reserve.sort.data.ptreve_reel}}</span> <span class="display-label flex-grow">{{reserve.sort.name}}</span>
<span class="flex-shrink">r{{reserve.sort.data.ptreve_reel}}</span>
<span class="flex-shrink">{{reserve.coord}}</span>
<span>{{caseTmr-label reserve.coord}}</span>
<div class="item-controls flex-shrink">
<a class="item-control item-delete flex-shrink" title="Supprimer"><i class="fas fa-trash"></i></a>
</div>
</li> </li>
{{/each}} {{/each}}
</ul> </ul>
@ -451,8 +479,8 @@
<ul class="item-list"> <ul class="item-list">
{{#each meditations as |meditation key|}} {{#each meditations as |meditation key|}}
<li class="item flexrow" data-item-id="{{meditation._id}}" data-attribute="{{key}}"> <li class="item flexrow" data-item-id="{{meditation._id}}" data-attribute="{{key}}">
<span class="meditation-label"><a data-id="{{meditation._id}}">{{meditation.name}} - {{meditation.data.competence}}</a></span> <span class="meditation-label flex-grow"><a data-item-id="{{meditation._id}}">{{meditation.name}} - {{meditation.data.competence}}</a></span>
<div class="item-controls"> <div class="item-controls flex-shrink">
<a class="item-control item-edit" title="Editer"><i class="fas fa-edit"></i></a> <a class="item-control item-edit" title="Editer"><i class="fas fa-edit"></i></a>
<a class="item-control item-delete" title="Supprimer"><i class="fas fa-trash"></i></a> <a class="item-control item-delete" title="Supprimer"><i class="fas fa-trash"></i></a>
</div> </div>
@ -466,8 +494,8 @@
<ul class="flex-group-left"> <ul class="flex-group-left">
{{#each queues as |queue key|}} {{#each queues as |queue key|}}
<li class="item flexrow" data-attribute={{key}} data-item-id="{{queue._id}}"> <li class="item flexrow" data-attribute={{key}} data-item-id="{{queue._id}}">
<span class="queuesouffle-label"> <a data-item-id="{{queue._id}}">{{queue.name}}</a></span> <span class="display-label flex-grow"><a data-item-id="{{queue._id}}">{{queue.name}}</a></span>
<div class="item-controls"> <div class="item-controls flex-shrink">
<a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a> <a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
</div> </div>
</li> </li>
@ -477,8 +505,8 @@
<ul class="item-list"> <ul class="item-list">
{{#each souffles as |souffle key|}} {{#each souffles as |souffle key|}}
<li class="item flexrow" data-attribute={{key}} data-item-id="{{souffle._id}}"> <li class="item flexrow" data-attribute={{key}} data-item-id="{{souffle._id}}">
<span class="queuesouffle-label"> <a data-item-id="{{souffle._id}}">{{souffle.name}}</a></span> <span class="display-label flex-grow"><a data-item-id="{{souffle._id}}">{{souffle.name}}</a></span>
<div class="item-controls"> <div class="item-controls flex-shrink">
<a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a> <a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
</div> </div>
</li> </li>
@ -488,8 +516,8 @@
<ul class="item-list"> <ul class="item-list">
{{#each tetes as |tete key|}} {{#each tetes as |tete key|}}
<li class="item flexrow" data-attribute={{key}} data-item-id="{{tete._id}}"> <li class="item flexrow" data-attribute={{key}} data-item-id="{{tete._id}}">
<span class="queuesouffle-label"> <a data-item-id="{{tete._id}}">{{tete.name}}</a></span> <span class="display-label flex-grow"><a data-item-id="{{tete._id}}">{{tete.name}}</a></span>
<div class="item-controls"> <div class="item-controls flex-shrink">
<a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a> <a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
</div> </div>
</li> </li>
@ -499,8 +527,8 @@
<ul class="item-list"> <ul class="item-list">
{{#each ombres as |ombre key|}} {{#each ombres as |ombre key|}}
<li class="item flexrow" data-attribute={{key}} data-item-id="{{ombre._id}}"> <li class="item flexrow" data-attribute={{key}} data-item-id="{{ombre._id}}">
<span class="queuesouffle-label"> <a data-item-id="{{ombre._id}}">{{ombre.name}}</a></span> <span class="display-label flex-grow"><a data-item-id="{{ombre._id}}">{{ombre.name}}</a></span>
<div class="item-controls"> <div class="item-controls flex-shrink">
<a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a> <a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
</div> </div>
</li> </li>
@ -512,8 +540,12 @@
<ul class="item-list"> <ul class="item-list">
{{#each hautreve.rencontres as |rencontre key|}} {{#each hautreve.rencontres as |rencontre key|}}
<li class="item flexrow" data-item-id="{{key}}" data-attribute="{{key}}"> <li class="item flexrow" data-item-id="{{key}}" data-attribute="{{key}}">
<span class="case-label"><a data-id="{{key}}">{{rencontre.rencontre.name}} - {{rencontre.coord}} {{#if rencontre.rencontre.date}}({{rencontre.rencontre.date}} - {{rencontre.rencontre.heure}}){{/if}}</a></span> <span class="display-label flex-grow"><a data-item-id="{{key}}">{{rencontre.rencontre.name}} - {{rencontre.coord}}</a></span>
<div class="item-controls"> <span class="flex-shrink">{{caseTmr-label reserve.coord}}</span>
{{#if rencontre.rencontre.date}}
<span>({{rencontre.rencontre.date}} - {{rencontre.rencontre.heure}})</span>
{{/if}}
<div class="item-controls flex-shrink">
<a class="item-control rencontre-delete" title="Supprimer"><i class="fas fa-trash"></i></a> <a class="item-control rencontre-delete" title="Supprimer"><i class="fas fa-trash"></i></a>
</div> </div>
</li> </li>
@ -523,11 +555,11 @@
<h3>Cases Spéciales:</h3> <h3>Cases Spéciales:</h3>
<ul class="item-list"> <ul class="item-list">
{{#each hautreve.casesTmr as |casetmr key|}} {{#each hautreve.casesTmr as |casetmr key|}}
<li class="item" data-item-id="{{casetmr._id}}" data-attribute="{{key}}"> <li class="item flexrow" data-item-id="{{casetmr._id}}" data-attribute="{{key}}">
<span class="item-controls"> <span class="display-label"><a data-item-id="{{casetmr._id}}">{{casetmr.name}}</a></span>
<span class="item-controls flex-shrink">
<a class="item-control item-delete" title="Supprimer"><i class="fas fa-trash"></i></a> <a class="item-control item-delete" title="Supprimer"><i class="fas fa-trash"></i></a>
</span> </span>
<span class="case-label"><a data-id="{{casetmr._id}}">{{casetmr.name}}</a></span>
</li> </li>
{{/each}} {{/each}}
</ul> </ul>
@ -544,7 +576,7 @@
<span class="competence-title competence-label">{{piece.name}}</span> <span class="competence-title competence-label">{{piece.name}}</span>
<span class="competence-title competence-label">{{piece.data.quantite}}</span> <span class="competence-title competence-label">{{piece.data.quantite}}</span>
<span class="competence-title"><a class="monnaie-plus">+</a><a class="monnaie-moins">-</a></span> <span class="competence-title"><a class="monnaie-plus">+</a><a class="monnaie-moins">-</a></span>
<div class="item-controls"> <div class="item-controls flex-shrink">
<a class="item-control item-edit" title="Editer"><i class="fas fa-edit"></i></a> <a class="item-control item-edit" title="Editer"><i class="fas fa-edit"></i></a>
<a class="item-control item-delete" title="Supprimer"><i class="fas fa-trash"></i></a> <a class="item-control item-delete" title="Supprimer"><i class="fas fa-trash"></i></a>
</div> </div>
@ -589,7 +621,7 @@
<li class="item flexrow list-item" data-actor-id="{{monture.id}}"> <li class="item flexrow list-item" data-actor-id="{{monture.id}}">
<img class="sheet-competence-img" src="{{monture.img}}" title="{{monture.name}}"/> <img class="sheet-competence-img" src="{{monture.img}}" title="{{monture.name}}"/>
<span class="competence-title subacteur-label"><a>{{monture.name}}</a></span> <span class="competence-title subacteur-label"><a>{{monture.name}}</a></span>
<div class="item-controls"> <div class="item-controls flex-shrink">
<a class="item-control subacteur-delete" title="Supprimer"><i class="fas fa-trash"></i></a> <a class="item-control subacteur-delete" title="Supprimer"><i class="fas fa-trash"></i></a>
</div> </div>
</li> </li>
@ -604,7 +636,7 @@
<span class="competence-title subacteur-label"><a>{{vehicule.name}}</a></span> <span class="competence-title subacteur-label"><a>{{vehicule.name}}</a></span>
<span class="competence-title">{{vehicule.categorie}}</span> <span class="competence-title">{{vehicule.categorie}}</span>
<span class="competence-title">{{vehicule.structure}}</span> <span class="competence-title">{{vehicule.structure}}</span>
<div class="item-controls"> <div class="item-controls flex-shrink">
<a class="item-control subacteur-delete" title="Supprimer"><i class="fas fa-trash"></i></a> <a class="item-control subacteur-delete" title="Supprimer"><i class="fas fa-trash"></i></a>
</div> </div>
</li> </li>
@ -617,7 +649,7 @@
<li class="item flexrow list-item" data-actor-id="{{suivant.id}}"> <li class="item flexrow list-item" data-actor-id="{{suivant.id}}">
<img class="sheet-competence-img" src="{{suivant.img}}" title="{{suivant.name}}"/> <img class="sheet-competence-img" src="{{suivant.img}}" title="{{suivant.name}}"/>
<span class="competence-title subacteur-label"><a>{{suivant.name}}</a></span> <span class="competence-title subacteur-label"><a>{{suivant.name}}</a></span>
<div class="item-controls"> <div class="item-controls flex-shrink">
<a class="item-control subacteur-delete" title="Supprimer"><i class="fas fa-trash"></i></a> <a class="item-control subacteur-delete" title="Supprimer"><i class="fas fa-trash"></i></a>
</div> </div>
</li> </li>

View File

@ -0,0 +1,11 @@
<img class="chat-icon" src="{{competence.img}}" alt="{{competence.name}}" />
<h4>{{alias}} lit le signe {{signe.name}}</h4>
{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.html"}}
<hr>
<div>
{{#if rolled.isSuccess}}
Vous avez gagné {{xpSort}} points d'expérience en sorts dans la {{competence.name}}.
{{else}}
Vous n'avez pas pu interpréter le signe draconique.
{{/if}}
</div>

View File

@ -6,11 +6,10 @@
<hr> <hr>
<div> <div>
{{#if rolled.isSuccess}} {{#if rolled.isSuccess}}
{{alias}} aperçoit un signe Draconique fugitif, qu'il faut aller lire en <strong>{{meditation.data.tmr}}</strong> en réussissant un test <strong>d'INTELLECT/Draconic à {{diffLecture}}</strong>. Vous apercevez un signe draconique éphémère, qu'il faut aller lire en <strong>{{meditation.data.tmr}}</strong>.
Selon le résultat de votre lecture, vous gagnerez les points suivants en Sort: 3 pour une Normale, 5 pour une Significative, 10 pour une Particulière.
{{else}} {{else}}
{{alias}} a échoué dans sa méditation et ne voit aucun signe Draconique. Votre méditation ne porte pas ses fruits, vous ne voyez aucun signe Draconique.
{{/if}} {{/if}}
<br><span>Vous vous êtes fatigué de 2 cases.</span> <br><span>Vous vous êtes fatigué de 2 cases.</span>
{{#if rolled.isETotal}}<br><span>Votre échec total augmente de 1 la difficulté de la méditation!</span>{{/if~}} {{#if rolled.isEPart}}<br><span>Votre échec {{#if rolled.isETotal}}total{{else}}particulier{{/if}} augmente de 1 la difficulté de la méditation!</span>{{/if~}}
</div> </div>

View File

@ -0,0 +1,7 @@
<h4><img class="chat-icon" src="{{signe.img}}" alt="{{signe.name}}" />
{{alias}} perçoit {{signe.name}}
</h4>
<p>Pour le lire ce signe draconique, rendez-vous dans les
Terres Médianes du Rêve et trouvez une case de résonnance.
{{#if signe.data.ephemere}}C'est un signe éphémère, qui ne restera présent que pour {{signe.data.duree}}{{/if}}
</p>

View File

@ -0,0 +1,4 @@
<h4><img class="chat-icon" src="systems/foundryvtt-reve-de-dragon/icons/tmr/signe_draconique.webp" alt="Signe draconique" />
{{alias}} peut lire un signe draconique
</h4>
<p>Vous venez de trouver une terre de résonance en {{typeTMR}}, vous pouvez le lire un signe draconique.</p>

View File

@ -0,0 +1,52 @@
<form class="skill-roll-dialog">
<div>
<h4>Paramétrer le signe draconique
<span class="chat-card-button-area">
<a class="signe-aleatoire chat-card-button">Signe aléatoire</a>
</span>
<br><input type="text" name="signe.name" value="{{signe.name}}" data-dtype="String" />
</h4>
</div>
<div class="form-group">
<label for="signe.data.difficulte">Difficulte</label>
<input type="number" name="signe.data.difficulte" value="{{signe.data.difficulte}}" data-dtype="Number" />
</div>
<div class="form-group">
<label for="signe.data.valeur.norm">Expérience en sorts</label>
<div class="flexrow">
<input class="signe-xp-sort" type="number" name="signe.data.valeur.norm" data-typereussite="norm"
value="{{signe.data.valeur.norm}}" min="1" max="100" data-dtype="Number" />
<span>Sign.</span>
<input class="signe-xp-sort" type="number" name="signe.data.valeur.sign" data-typereussite="sign"
value="{{signe.data.valeur.sign}}" min="1" max="100" data-dtype="Number" />
<span>Part.</span>
<input class="signe-xp-sort" type="number" name="signe.data.valeur.part" data-typereussite="part"
value="{{signe.data.valeur.part}}" min="1" max="100" data-dtype="Number" />
</div>
</div>
<div class="form-group flexrow">
<label for="signe.data.ephemere">Ephémère</label>
<input class="flex-shrink" type="checkbox" name="signe.data.ephemere" {{#if signe.data.ephemere}}checked{{/if}} />
<span>
<input type="text" name="signe.data.duree" value="{{signe.data.duree}}" data-dtype="String" />
</span>
</div>
<div class="form-group">
<label for="tmrs">Terres médianes</label>
<select class="select-tmr" name="tmrs" id="tmrs" size="{{tmrs.length}}" multiple>
{{#each tmrs as |tmr key|}}
<option value="{{tmr.name}}" {{#if tmr.selected}}selected{{/if}}>{{tmr.name}}</option>
{{/each}}
</select>
</div>
<div class="form-group">
<label for="actors">Haut-rêvants concernés</label>
<select class="select-actor" id="actors" size="7" multiple>
{{#each actors as |actor key|}}
<option value="{{actor.name}}" data-actor-id="{{actor._id}}" {{#if actor.selected}}selected{{/if}}>{{actor.name}}</option>
{{/each}}
</select>
</div>
</form>

View File

@ -0,0 +1,48 @@
{{log 'lecture signe draconique' this}}
<form class="dialog-roll-sort">
<h2>Lire le signe draconique
<select name="signe-draconique" class="roll-signedraconique flex-grow" data-dtype="String">
{{#select signe}}
{{#each signes as |signe key|}}
<option value={{key}}>{{this.name}}</option>
{{/each}}
{{/select}}
</select>
</h2>
<img class="chat-icon" src="{{competence.img}}" alt="{{competence.name}}" />
<div class="grid grid-2col">
<div class="flex-group-left">
<div class="flexrow">
<label for="tmr">TMR - {{tmr.coord}}:</label><label name="tmr">{{tmr.label}}</label>
</div>
<div class="flexrow">
<label for="carac">{{selectedCarac.label}}:</label><label name="carac">{{selectedCarac.value}}</label>
</div>
</div>
<div class="flex-group-left">
<div class="flexrow">
<label for="competence">Draconic:</label>
<select name="competence" class="roll-draconic" data-dtype="String">
{{#select draconic}}
{{#each draconicList as |draconic key|}}
<option value={{key}}>{{draconic.name}} : {{numberFormat draconic.data.niveau decimals=0 sign=true}}
</option>
{{/each}}
{{/select}}
</select>
</div>
<div class="flexrow">
<label>Difficulté</label>
<label class="signe-difficulte">{{diffLibre}}</label>
</div>
{{>"systems/foundryvtt-reve-de-dragon/templates/partial-roll-diffCondition.html"}}
<div id="tableAjustements" class="flexrow"></div>
</div>
</div>
<div id="tableResolution"></div>
<div id="tableProbaReussite"></div>
</form>
<script>
</script>

View File

@ -1,4 +1,3 @@
{{log 'lancer de sort' this}}
<form class="dialog-roll-sort"> <form class="dialog-roll-sort">
<h2>Lancer le <span class="sort-ou-rituel">{{#if sort.data.isrituel}}rituel{{else}}sort{{/if}}</span>: <h2>Lancer le <span class="sort-ou-rituel">{{#if sort.data.isrituel}}rituel{{else}}sort{{/if}}</span>:
<select name="sort" class="roll-sort flex-grow" data-dtype="String"> <select name="sort" class="roll-sort flex-grow" data-dtype="String">

View File

@ -14,8 +14,11 @@
<img class="small-button-direction" id='dir-bottom' src='systems/foundryvtt-reve-de-dragon/styles/img/ui/dir-bottom.svg'> <img class="small-button-direction" id='dir-bottom' src='systems/foundryvtt-reve-de-dragon/styles/img/ui/dir-bottom.svg'>
<img class="small-button-direction" id='dir-bottom-right' src='systems/foundryvtt-reve-de-dragon/styles/img/ui/dir-bottom-right.svg'> <img class="small-button-direction" id='dir-bottom-right' src='systems/foundryvtt-reve-de-dragon/styles/img/ui/dir-bottom-right.svg'>
</div> </div>
<div class="flex-group-center"> <div class="flex-group-center lire-signe-draconique">
<a id="lancer-sort">Lancer un Sort</a> <a>Lire un signe draconique</a>
</div>
<div class="flex-group-center lancer-sort">
<a>Lancer un Sort</a>
</div> </div>
<hr> <hr>
<div class="flex-group-center"> <div class="flex-group-center">

View File

@ -29,15 +29,15 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="xp">Difficulté</label> <label for="xp">Difficulté</label>
<input class="attribute-value" type="text" name="data.difficulte" value="{{data.difficulte}}" data-dtype="Number"/> <input class="attribute-value" type="number" name="data.difficulte" value="{{data.difficulte}}" data-dtype="Number"/>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="xp">Points de tâches</label> <label for="xp">Points de tâches</label>
<input class="attribute-value" type="text" name="data.points_de_tache" value="{{data.points_de_tache}}" data-dtype="Number"/> <input class="attribute-value" type="number" name="data.points_de_tache" value="{{data.points_de_tache}}" data-dtype="Number"/>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="xp">Expérience</label> <label for="xp">Expérience</label>
<input class="attribute-value" type="text" name="data.xp" value="{{data.xp}}" data-dtype="String"/> <input class="attribute-value" type="number" name="data.xp" value="{{data.xp}}" data-dtype="Number"/>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="xp">Niveau minimum</label> <label for="xp">Niveau minimum</label>
@ -49,15 +49,15 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="xp">Encombrement </label> <label for="xp">Encombrement </label>
<input class="attribute-value" type="text" name="data.encombrement" value="{{data.encombrement}}" data-dtype="Number"/> <input class="attribute-value" type="number" name="data.encombrement" value="{{data.encombrement}}" data-dtype="Number"/>
</div> </div>
<div class="form-group"> <div class="form-group">
<label>Quantité </label> <label>Quantité </label>
<input class="attribute-value" type="text" name="data.quantite" value="{{data.quantite}}" data-dtype="Number" /> <input class="attribute-value" type="number" name="data.quantite" value="{{data.quantite}}" data-dtype="Number" />
</div> </div>
<div class="form-group item-cout"> <div class="form-group item-cout">
<label for="xp">Prix (sols) </label> <label for="xp">Prix (sols) </label>
<input class="attribute-value" type="text" name="data.cout" value="{{data.cout}}" data-dtype="Number"/> <input class="attribute-value" type="number" name="data.cout" value="{{data.cout}}" data-dtype="Number"/>
</div> </div>
<div class="flexcol"> <div class="flexcol">
<span><label>Description : </label></span> <span><label>Description : </label></span>

View File

@ -0,0 +1,56 @@
<form class="{{cssClass}}" autocomplete="off">
<header class="sheet-header">
<img class="profile-img" src="{{img}}" data-edit="img" title="{{name}}" />
<div class="header-fields">
<h1 class="charname"><input name="name" type="text" value="{{name}}" placeholder="Name" /></h1>
<a class="signe-aleatoire chat-card-button">Signe aléatoire</a>
</div>
</header>
{{!-- Sheet Body --}}
<section class="sheet-body">
<div class="form-group">
<label for="data.difficulte">Difficulte</label>
<input class="attribute-value" type="number" name="data.difficulte" value="{{data.difficulte}}"
data-dtype="Number" />
</div>
<div class="form-group">
<label for="data.valeur.norm">Expérience en sorts</label>
<div class="flexrow">
<input class="signe-xp-sort" type="number" name="data.valeur.norm" data-typereussite="norm"
value="{{data.valeur.norm}}" min="1" max="100" data-dtype="Number" />
<span>Sign.</span>
<input class="signe-xp-sort" type="number" name="data.valeur.sign" data-typereussite="sign"
value="{{data.valeur.sign}}" min="1" max="100" data-dtype="Number" />
<span>Part.</span>
<input class="signe-xp-sort" type="number" name="data.valeur.part" data-typereussite="part"
value="{{data.valeur.part}}" min="1" max="100" data-dtype="Number" />
</div>
</div>
<div class="form-group">
<label for="data.ephemere">Ephémère</label>
<input class="attribute-value" type="checkbox" name="data.ephemere" {{#if data.ephemere}}checked{{/if}} />
</div>
{{#if data.ephemere}}
<div class="form-group">
<label for="data.duree">Durée</label>
<input class="attribute-value" type="text" name="data.duree" value="{{data.duree}}" data-dtype="String" />
</div>
{{/if}}
<div class="form-group">
<label for="tmrs">Terres médianes</label>
<select class="select-tmr attribute-value" name="tmrs" id="tmrs" size={{tmrs.length}} multiple />
{{#each tmrs as |tmr key|}}
<option class="option-tmr" value="{{tmr.name}}" {{#if tmr.selected}}selected{{/if}}>{{tmr.name}}</option>
{{/each}}
</select>
</div>
<div class="flexcol">
<span><label>Description : </label></span>
<div class="form-group editor">
{{editor content=data.description target="data.description" button=true owner=owner editable=editable}}
</div>
</div>
</section>
</form>