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
todo.txt
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"));
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 => {
const li = $(ev.currentTarget).parents(".item");
const rencontreKey = li.data("item-id");
@ -428,26 +433,6 @@ export class RdDActorSheet extends ActorSheet {
html.find('.enlever-tous-effets').click((event) => {
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) => {
let myID = event.currentTarget.attributes['data-item-id'].value;
RdDUtility.toggleAfficheContenu(myID);

View File

@ -19,6 +19,7 @@ import { RdDItemArme } from "./item-arme.js";
import { RdDAlchimie } from "./rdd-alchimie.js";
import { StatusEffects } from "./status-effects.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { RdDItemSigneDraconique } from "./item-signedraconique.js";
import { ReglesOptionelles } from "./regles-optionelles.js";
import { TMRRencontres } from "./tmr-rencontres.js";
import { Poetique } from "./poetique.js";
@ -193,7 +194,7 @@ export class RdDActor extends Actor {
}
/* -------------------------------------------- */
isHautRevant() {
return Misc.templateData(this).attributs.hautrevant.value != ""
return this.isPersonnage() && Misc.templateData(this).attributs.hautrevant.value != ""
}
/* -------------------------------------------- */
getFatigueActuelle() {
@ -650,8 +651,7 @@ export class RdDActor extends Actor {
}
}
else {
const roll = new Roll("1dr").evaluate();
let deRecuperation = roll.total;
let deRecuperation = await RdDDice.rollTotal("1dr");
console.log("recuperationReve", deRecuperation);
if (deRecuperation >= 7) {
// Rêve de Dragon !
@ -743,7 +743,7 @@ export class RdDActor extends Actor {
// TODO: un dialogue pour demander le type de tête?
rollData.tete = true;
}
rollData.poesie = Poetique.getExtrait();
rollData.poesie = await Poetique.getExtrait();
ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
@ -1088,11 +1088,17 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
computeIsHautRevant() {
const tplData = Misc.templateData(this);
tplData.attributs.hautrevant.value = this.listItemsData('tete').find(it => Grammar.toLowerCaseNoAccent(it.name) == 'don de haut-reve')
if (this.isPersonnage()) {
Misc.templateData(this).attributs.hautrevant.value = this.hasItemNamed('tete', 'don de haut-reve')
? "Haut rêvant"
: "";
}
}
hasItemNamed(type, name) {
name = Grammar.toLowerCaseNoAccent(name);
return this.listItemsData(type).find(it => Grammar.toLowerCaseNoAccent(it.name) == name);
}
/* -------------------------------------------- */
async computeEncombrementTotalEtMalusArmure() {
@ -1184,7 +1190,7 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
async ajouterRefoulement(value = 1) {
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) {
refoulement = 0;
await this.ajouterSouffle({ chat: true });
@ -1266,7 +1272,7 @@ export class RdDActor extends Actor {
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name)
});
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.cacheTMR();
return tmr;
@ -1395,25 +1401,6 @@ export class RdDActor extends Actor {
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) {
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);
}
/* -------------------------------------------- */
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() {
let myRoll = new Roll("1d20").roll();
myRoll.showDice = true;
await RdDDice.show(myRoll);
const actorData = Misc.data(this);
let msgText = "Jet d'Endurance : " + myRoll.total + " / " + actorData.data.sante.endurance.value + "<br>";
if (myRoll.total == 1 || (myRoll.total != 20 && myRoll.total <= actorData.data.sante.endurance.value)) {
msgText += `${this.name} a réussi son Jet d'Endurance !`;
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 endurance = actorData.data.sante.endurance.value;
const result = await this._jetEndurance(actorData.data.sante.endurance.value)
const message = {
content: msgText,
content: "Jet d'Endurance : " + result.roll.total + " / " + endurance + "<br>",
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);
}
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() {
let myRoll = new Roll("1d20").roll();
myRoll.showDice = true;
await RdDDice.show(myRoll);
let roll = await RdDDice.roll("1d20", { showDice: true });
const actorData = Misc.data(this);
let msgText = "Jet de Vie : " + myRoll.total + " / " + actorData.data.sante.vie.value + "<br>";
if (myRoll.total <= actorData.data.sante.vie.value) {
let msgText = "Jet de Vie : " + roll.total + " / " + actorData.data.sante.vie.value + "<br>";
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)";
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)";
}
} else {
msgText += "Jet échoué, vous perdez 1 point de vie";
await this.santeIncDec("vie", -1);
if (myRoll.total == 20) {
if (roll.total == 20) {
msgText += "Votre personnage est mort !!!!!";
}
}
@ -1582,8 +1592,7 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
async jetDeMoral(situation, messageReussi = undefined, messageManque = undefined) {
let jetMoral = new Roll("1d20").roll();
RdDDice.show(jetMoral);
let jetMoral = await RdDDice.roll("1d20", { showDice: true });
let moralActuel = Misc.toInt(Misc.templateData(this).compteurs.moral.value);
const difficulte = 10 + moralActuel;
const succes = jetMoral.total <= difficulte;
@ -1687,7 +1696,7 @@ export class RdDActor extends Actor {
RdDResolutionTable.displayRollData(jetVieView, this, 'chat-resultat-ethylisme.html');
if (rollEthylisme.isEchec) {
let enduranceLostRoll = new Roll("1d6").roll();
let enduranceLostRoll = await RdDDice.roll("1d6");
// enduranceLostRoll.showDice = true;
RdDDice.show(enduranceLostRoll);
let enduranceLost = enduranceLostRoll.total;
@ -2097,9 +2106,11 @@ export class RdDActor extends Actor {
let draconicList = this.computeDraconicAndSortIndex(sortList);
const actorData = Misc.data(this);
const reve = duplicate(actorData.data.carac.reve);
let rollData = {
forceCarac: { 'reve': duplicate(actorData.data.carac.reve) },
selectedCarac: duplicate(actorData.data.carac.reve),
carac: { 'reve': reve },
forceCarac: { 'reve': reve },
selectedCarac: reve,
draconicList: draconicList,
sortList: sortList,
competence: draconicList[0],
@ -2107,10 +2118,8 @@ export class RdDActor extends Actor {
tmr: TMRUtility.getTMR(coord),
diffLibre: RdDItemSort.getDifficulte(sortList[0], -7), // Per default at startup
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,
{
html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-sort.html',
@ -2320,6 +2329,11 @@ export class RdDActor extends Actor {
dialog.render(true);
}
/* -------------------------------------------- */
async _competenceResult(rollData) {
RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-competence.html')
}
/* -------------------------------------------- */
async creerTacheDepuisLivre(item, options = { renderSheet: true }) {
const itemData = Misc.data(item);
@ -2544,24 +2558,15 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
async rollMeditation(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 = {
competence: competence,
meditation: meditation,
conditionMeditation: {
isHeure: false,
isVeture: false,
isComportement: false,
isPurification: false,
},
competence: duplicate(Misc.data(this.getCompetence(meditation.data.competence))),
meditation: duplicate(meditation),
conditionMeditation: { isHeure: false, isVeture: false, isComportement: false, isPurification: false },
diffConditions: 0,
use: { libre: false, conditions: true, },
carac: {}
carac: { "intellect": Misc.templateData(this).carac.intellect }
};
meditationData.carac["intellect"] = Misc.templateData(this).carac["intellect"];
console.log("rollMeditation !!!", meditationData);
meditationData.competence.data.defaut_carac = "intellect"; // Meditation = tjs avec intellect
const dialog = await RdDRoll.create(this, meditationData,
{
@ -2573,7 +2578,7 @@ export class RdDActor extends Actor {
label: "Jet de méditation",
callbacks: [
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) }
]
});
@ -2584,27 +2589,92 @@ export class RdDActor extends Actor {
async _meditationResult(meditationData) {
this.santeIncDec("fatigue", 2);
meditationData.diffLecture = -7;
if (meditationData.rolled.isPart)
meditationData.diffLecture = 0;
else if (meditationData.rolled.isSign)
meditationData.diffLecture = -3;
const signeData = RdDItemSigneDraconique.prepareSigneDraconiqueMeditation(meditationData.meditation, meditationData.rolled)
if (signeData) {
await this.createEmbeddedDocuments("Item", [signeData]);
}
RdDResolutionTable.displayRollData(meditationData, this.name, 'chat-resultat-meditation.html');
}
/* -------------------------------------------- */
_meditationETotal(meditationData) {
meditationData.meditation.data.malus--;
this.updateEmbeddedDocuments('Item', [meditationData.meditation]);
_meditationEPart(meditationData) {
this.updateEmbeddedDocuments('Item', [{ _id: meditation._id, 'data.malus': meditationData.meditation.data.malus - 1 }]);
}
/* -------------------------------------------- */
_getSignesDraconiques(coord) {
const type = TMRUtility.getTMRType(coord);
return this.listItemsData("signedraconique").filter(it => it.data.typesTMR.includes(type));
}
/* -------------------------------------------- */
async _competenceResult(rollData) {
RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-competence.html')
isResonanceSigneDraconique(coord) {
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),
draconic: this.getDraconicList(),
sort: this.getSortList(),
signes: this.listItemsData("signedraconique"),
caracReve: actorData.data.carac.reve.value,
pointsReve: this.getReveActuel(),
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 armeData = attackerRoll.arme;
let protection = 0;
const armures = this.items.map(it => Misc.data(it))
.filter(it => it.type == "armure" && it.data.equipe);
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) {
this._deteriorerArmure(itemData, dmg);
dmg = 0;
@ -2972,7 +3043,7 @@ export class RdDActor extends Actor {
console.log("encaisserDommages", rollData)
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
const perteVie = this.isEntiteCauchemar()
@ -3011,29 +3082,34 @@ export class RdDActor extends Actor {
}
/* -------------------------------------------- */
jetEncaissement(rollData) {
const roll = new Roll("2d10").roll();
roll.showDice = true;
RdDDice.show(roll, game.settings.get("core", "rollMode"));
async jetEncaissement(rollData) {
const roll = await RdDDice.roll("2d10", { showDice: true });
const armure = this.computeArmure(rollData);
const armure = await this.computeArmure(rollData);
const jetTotal = roll.total + rollData.dmg.total - armure;
let encaissement = RdDUtility.selectEncaissement(jetTotal, rollData.dmg.mortalite)
let over20 = Math.max(jetTotal - 20, 0);
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.roll = roll;
encaissement.armure = armure;
encaissement.total = jetTotal;
encaissement.vie = RdDUtility._evaluatePerte(encaissement.vie, over20);
encaissement.endurance = RdDUtility._evaluatePerte(encaissement.endurance, over20);
encaissement.vie = await RdDActor._evaluatePerte(encaissement.vie, over20);
encaissement.endurance = await RdDActor._evaluatePerte(encaissement.endurance, over20);
encaissement.penetration = rollData.arme?.data.penetration ?? 0;
return encaissement;
}
/* -------------------------------------------- */
static async _evaluatePerte(formula, over20) {
let perte = new Roll(formula, { over20: over20 });
await perte.evaluate({ async: true });
return perte.total;
}
/* -------------------------------------------- */
ajouterBlessure(encaissement) {
const actorData = Misc.data(this);
@ -3615,7 +3691,7 @@ export class RdDActor extends Actor {
potionData.reussiteReve = true;
potionData.aphasiePermanente = false;
if (potionData.data.reposalchimique) {
let chanceAphasie = new Roll("1d100").evaluate({ async: false }).total;
let chanceAphasie = await RdDDice.rollTotal("1d100");
if (chanceAphasie <= potionData.data.pr) {
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 */
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 - 192;
const bodyHeight = position.height - sheetHeader[0].clientHeight;
sheetBody.css("height", bodyHeight);
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() {
return Misc.data(this).type == 'conteneur';
}
isVide() {
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
@ -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) {
return [...new Set(array)];
}

View File

@ -1,4 +1,5 @@
import { Misc } from "./misc.js"
import { RdDDice } from "./rdd-dice.js";
const poesieHautReve = [
{
@ -64,8 +65,8 @@ const poesieHautReve = [
]
export class Poetique {
static getExtrait(){
return Misc.rollOneOf(poesieHautReve);
static async getExtrait(){
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 { RdDUtility } from "./rdd-utility.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/'
@ -124,9 +126,9 @@ export class RdDCalendrier extends Application {
}
/* -------------------------------------------- */
ajouterNombreAstral(index) {
async ajouterNombreAstral(index) {
return {
nombreAstral: new Roll("1d12").evaluate( {async:false} ).total,
nombreAstral: await RdDDice.rollTotal("1dh"),
valeursFausses: [],
index: index
}
@ -278,11 +280,10 @@ export class RdDCalendrier extends Application {
request.isValid = true;
if (!request.rolled.isSuccess) {
request.isValid = false;
let nbAstralFaux = new Roll("1d11").evaluate( { async: false} ).total;
nbAstral = nbAstral==nbAstralFaux ? 12 : nbAstralFaux;
nbAstral = await RdDDice.rollTotal("1dhr"+nbAstral);
// Mise à jour des nombres astraux du joueur
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);
}
request.nbAstral = nbAstral;

View File

@ -1,5 +1,6 @@
/* -------------------------------------------- */
import { DialogCreateSigneDraconique } from "./dialog-create-signedraconique.js";
import { RdDItemCompetence } from "./item-competence.js";
import { Misc } from "./misc.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:
<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;
}
}
@ -271,16 +283,14 @@ export class RdDCommands {
/* -------------------------------------------- */
async rollDeDraconique(msg) {
let ddr = new Roll("1dr + 7").evaluate();
ddr.showDice = true;
await RdDDice.showDiceSoNice(ddr);
RdDCommands._chatAnswer(msg, `Lancer d'un Dé draconique: ${ddr.total}`);
let ddr = await RdDDice.rollTotal("1dr + 7", { showDice:true });
RdDCommands._chatAnswer(msg, `Lancer d'un Dé draconique: ${ddr}`);
}
getTMRAleatoire(msg, params) {
async getTMRAleatoire(msg, params) {
if (params.length < 2) {
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}`);
}
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);
}
evaluate() {
async evaluate() {
super.evaluate();
this.explode("x=8");
return this;
@ -73,7 +73,7 @@ export class DeDraconique extends Die {
super(termData);
}
evaluate() {
async evaluate() {
super.evaluate();
this.explode("x=7");
return this;
@ -124,6 +124,27 @@ export class RdDDice {
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) {
for (const system of Object.keys(dice3d.DiceFactory.systems)) {
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 { RdDItem } from "./item.js";
import { RdDDice } from "./rdd-dice.js";
import { RdDSigneDraconiqueItemSheet } from "./item-signedraconique-sheet.js";
/* -------------------------------------------- */
/* 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", RdDActorEntiteSheet, { types: ["entite"], makeDefault: true });
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 });
CONFIG.Combat.documentClass = RdDCombatManager;
@ -176,7 +182,7 @@ Hooks.once("init", async function () {
RdDDice.init();
RdDCommands.init();
RdDCombat.init();
RdDCombatManager.init(),
RdDCombatManager.init();
RdDTokenHud.init();
RdDActor.init();
RddCompendiumOrganiser.init();

View File

@ -1,14 +1,17 @@
import { Grammar } from "./grammar.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',
'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 {
static getName( msg, params ) {
let name = Misc.upperFirst( Misc.rollOneOf(words) + Misc.rollOneOf(words) )
static async getName( msg, params ) {
let name = Misc.upperFirst( await RdDDice.rollOneOf(words) + await RdDDice.rollOneOf(words) )
//console.log(name);
ChatMessage.create( { content: `Nom : ${name}`, whisper: ChatMessage.getWhisperRecipients("GM") } );
}

View File

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

View File

@ -205,6 +205,11 @@ export class RdDRoll extends Dialog {
this.updateRollResult();
$("#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) => {
let ptreve = Misc.toInt(event.currentTarget.value);
this.rollData.selectedSort.data.ptreve_reel = ptreve;
@ -276,6 +281,12 @@ export class RdDRoll extends Dialog {
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() {
let rollData = this.rollData;

View File

@ -8,31 +8,20 @@ export class RdDRollTables {
const table = await pack.getDocument(entry._id);
const draw = await table.draw({ displayChat: toChat, rollMode: "gmroll"});
console.log("RdDRollTables", tableName, toChat, ":", draw);
return draw;
return draw.results.length > 0 ? draw.results[0] : undefined;
}
/* -------------------------------------------- */
static async drawItemFromRollTable(tableName, toChat) {
const draw = await RdDRollTables.genericGetTableResult(tableName, toChat);
const drawnItemRef = draw.results.length > 0 ? draw.results[0] : undefined;
if (drawnItemRef.data.collection) {
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 drawItemFromRollTable(tableName, toChat = false) {
const drawResult = await RdDRollTables.genericGetTableResult(tableName, toChat);
const pack = game.packs.get(drawResult.data.collection);
return await pack.getDocument(drawResult.data.resultId);
}
/* -------------------------------------------- */
static async drawTextFromRollTable(tableName, toChat) {
const draw = await RdDRollTables.genericGetTableResult(tableName, toChat);
const drawnItemRef = draw.results.length > 0 ? draw.results[0] : undefined;
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;
const drawResult = await RdDRollTables.genericGetTableResult(tableName, toChat);
return drawResult.data.text;
}
/* -------------------------------------------- */

View File

@ -13,6 +13,7 @@ import { Draconique } from "./tmr/draconique.js";
import { Misc } from "./misc.js";
import { HtmlUtility } from "./html-utility.js";
import { ReglesOptionelles } from "./regles-optionelles.js";
import { RdDDice } from "./rdd-dice.js";
/* -------------------------------------------- */
export class RdDTMRDialog extends Dialog {
@ -142,20 +143,27 @@ export class RdDTMRDialog extends Dialog {
_tokenSortEnReserve(sortEnReserve) {
return EffetsDraconiques.sortReserve.token(this.pixiTMR, sortEnReserve.sort, () => sortEnReserve.coord);
}
_tokenDemiReve() {
const actorData = Misc.data(this.actor);
return EffetsDraconiques.demiReve.token(this.pixiTMR, actorData, () => actorData.data.reve.tmrpos.coord);
}
_updateDemiReve() {
this.notifierResonanceSigneDraconique(this._getActorCoord());
if (!this.cacheTMR) {
this._setTokenPosition(this.demiReve);
}
}
_getActorCoord() {
return Misc.data(this.actor).data.reve.tmrpos.coord;
}
/* -------------------------------------------- */
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 == 'bottom') pos.y += 1;
@ -178,22 +186,25 @@ export class RdDTMRDialog extends Dialog {
async activateListeners(html) {
super.activateListeners(html);
HtmlUtility._showControlWhen($(".appliquerFatigue"), ReglesOptionelles.isUsing("appliquer-fatigue"));
document.getElementById("tmrrow1").insertCell(0).append(this.pixiApp.view);
if (this.viewOnly) {
html.find('#lancer-sort').remove();
}
else {
// Roll Sort
html.find('#lancer-sort').click((event) => {
this.actor.rollUnSort(Misc.data(this.actor).data.reve.tmrpos.coord);
});
}
if (this.viewOnly) {
html.find('.lancer-sort').remove();
html.find('.lire-signe-draconique').remove();
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) => {
this.moveFromKey("top");
});
@ -213,7 +224,6 @@ export class RdDTMRDialog extends Dialog {
this.moveFromKey("bottom");
});
// 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();
if (ReglesOptionelles.isUsing("appliquer-fatigue")) {
@ -223,24 +233,27 @@ export class RdDTMRDialog extends Dialog {
// Le reste...
this.updateValuesDisplay();
let tmr = TMRUtility.getTMR(Misc.data(this.actor).data.reve.tmrpos.coord);
let tmr = TMRUtility.getTMR(this._getActorCoord());
await this.manageRencontre(tmr, () => {
this.postRencontre(tmr);
});
}
/* -------------------------------------------- */
updateValuesDisplay() {
let ptsreve = document.getElementById("tmr-pointsreve-value");
async updateValuesDisplay() {
const coord = this._getActorCoord();
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;
let tmrpos = document.getElementById("tmr-pos");
if (this.cacheTMR) {
tmrpos.innerHTML = '?? ('+ TMRUtility.getTMRType( actorData.data.reve.tmrpos.coord ) + ')';
tmrpos.innerHTML = '?? (' + TMRUtility.getTMRType(coord) + ')';
} else {
let tmr = TMRUtility.getTMR(actorData.data.reve.tmrpos.coord);
tmrpos.innerHTML = actorData.data.reve.tmrpos.coord + " (" + tmr.label + ")";
tmrpos.innerHTML = coord + " (" + TMRUtility.getTMRLabel(coord) + ")";
}
let etat = document.getElementById("tmr-etatgeneral-value");
@ -373,7 +386,7 @@ export class RdDTMRDialog extends Dialog {
rencontre: this.currentRencontre,
nbRounds: 1,
canClose: false,
tmr: TMRUtility.getTMR(Misc.data(this.actor).data.reve.tmrpos.coord)
tmr: TMRUtility.getTMR(this._getActorCoord())
}
await this._tentativeMaitrise(rencontreData);
@ -523,7 +536,7 @@ export class RdDTMRDialog extends Dialog {
if (rencontre) {
return rencontre;
}
let myRoll = new Roll("1d7").evaluate( { async: false} ).total;
let myRoll = await RdDDice.rollTotal("1d7");
if (TMRUtility.isForceRencontre() || myRoll == 7) {
return await this.rencontreTMRRoll(tmr, this.actor.isRencontreSpeciale());
}
@ -584,7 +597,7 @@ export class RdDTMRDialog extends Dialog {
await this._rollMaitriseCaseHumide(rollData);
return;
}
rollData.poesie = Poetique.getExtrait();
rollData.poesie = await Poetique.getExtrait();
ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
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;
rollData.poesie = Poetique.getExtrait();
rollData.poesie = await Poetique.getExtrait();
ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
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) {
let currentPos = TMRUtility.convertToCellPos(Misc.data(this.actor).data.reve.tmrpos.coord);
let currentPos = TMRUtility.convertToCellPos(this._getActorCoord());
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 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);
this.nettoyerRencontre();
}
@ -920,7 +934,6 @@ export class RdDTMRDialog extends Dialog {
// Gestion cases spéciales type Trou noir, etc
tmr = await this.manageTmrInnaccessible(tmr);
this.actor.updateCoordTMR(tmr.coord);
await this.actor.updateCoordTMR(tmr.coord);
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) {
if (!(this.viewOnly || this.currentRencontre)) {

View File

@ -7,6 +7,7 @@ import { Grammar } from "./grammar.js";
import { TMRUtility } from "./tmr-utility.js";
import { DialogItemAchat } from "./dialog-item-achat.js";
import { ReglesOptionelles } from "./regles-optionelles.js";
import { RdDDice } from "./rdd-dice.js";
/* -------------------------------------------- */
// 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-meditation-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-base.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-carac-xp.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'));
@ -271,6 +274,7 @@ export class RdDUtility {
formData.munitions = this.checkNull(formData.itemsByType['munition']);
formData.herbes = this.checkNull(formData.itemsByType['herbe']);
formData.sorts = this.checkNull(formData.itemsByType['sort']);
formData.signesdraconiques = this.checkNull(formData.itemsByType['signedraconique']);
formData.queues = this.checkNull(formData.itemsByType['queue']);
formData.souffles = this.checkNull(formData.itemsByType['souffle']);
formData.ombres = this.checkNull(formData.itemsByType['ombre']);
@ -441,8 +445,8 @@ export class RdDUtility {
}
/* -------------------------------------------- */
static getLocalisation(type = 'personnage') {
let result = new Roll("1d20").roll().total;
static async getLocalisation(type = 'personnage') {
let result = await RdDDice.rollTotal("1d20");
let txt = ""
if (type == 'personnage') {
if (result <= 3) txt = "Jambe, genou, pied, jarret";
@ -474,15 +478,6 @@ export class RdDUtility {
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) {
if (ReglesOptionelles.isUsing("appliquer-fatigue")) {

View File

@ -1,5 +1,6 @@
import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
import { RdDDice } from "./rdd-dice.js";
import { TMRUtility } 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: "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: "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 = [
@ -324,7 +325,7 @@ export class TMRRencontres {
return false;
}
if (!roll || roll <= 0 || roll > 100) {
roll = new Roll("1d100").evaluate().total;
roll = await RdDDice.rollTotal("1d100");
}
let rencontre = await TMRRencontres.getRencontreAleatoire(terrain, roll);
ChatMessage.create({
@ -356,15 +357,13 @@ export class TMRRencontres {
/* -------------------------------------------- */
static async getRencontreAleatoire(terrain, roll = undefined) {
if (!roll || roll <= 0 || roll > 100) {
roll = new Roll("1d100").evaluate({ async: false }).total;
roll = await RdDDice.rollTotal("1d100");
}
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 rencontre = duplicate(rencontresStandard.find(it => it.code == code));
rencontre.roll = roll;
await TMRRencontres.evaluerForceRencontre(rencontre);
//console.log(rencontre);
return rencontre;
}
@ -373,20 +372,14 @@ export class TMRRencontres {
const rencontre = duplicate(
(index && index >= 0 && index < mauvaisesRencontres.length)
? mauvaisesRencontres[index]
: Misc.rollOneOf(mauvaisesRencontres));
: await RdDDice.rollOneOf(mauvaisesRencontres));
await TMRRencontres.evaluerForceRencontre(rencontre);
return rencontre;
}
/* -------------------------------------------- */
static async evaluerForceRencontre(rencontre) {
if (TMRRencontres.isReveDeDragon(rencontre)) {
const ddr = new Roll("1dr + 7").evaluate();
rencontre.force = 7 + ddr.total;
}
else {
rencontre.force = new Roll(rencontre.force).evaluate({ async: false }).total;
}
rencontre.force = await new Roll(rencontre.force).evaluate().total;
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];
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
tmrData.newTMR = TMRUtility.getTMR(tmrData.sortReserve.coord);
} else {
// 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);
}
if (tmrData.sortReserve) {
@ -472,7 +465,7 @@ export class TMRRencontres {
static async _toubillonner(tmrDialog, actor, cases) {
let coord = Misc.templateData(actor).reve.tmrpos.coord;
for (let i = 0; i < cases; i++) {
coord = TMRUtility.deplaceTMRAleatoire(actor, coord).coord;
coord = await TMRUtility.deplaceTMRAleatoire(actor, coord).coord;
}
await tmrDialog.forceDemiRevePosition(coord)
}

View File

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

View File

@ -1,5 +1,6 @@
import { Grammar } from "../grammar.js";
import { Misc } from "../misc.js";
import { RdDDice } from "../rdd-dice.js";
import { tmrColors, tmrConstants, tmrTokenZIndex, TMRUtility } from "../tmr-utility.js";
import { Draconique } from "./draconique.js";
@ -31,7 +32,7 @@ export class Conquete extends Draconique {
async _creerConquete(actor, queue) {
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 conquete = Misc.rollOneOf(possibles);
let conquete =await RdDDice.rollOneOf(possibles);
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 }
async onActorCreateOwned(actor, souffle) {
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);
}

View File

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

View File

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

View File

@ -1,5 +1,6 @@
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";
export class Periple extends Draconique {
@ -13,7 +14,7 @@ export class Periple extends Draconique {
manualMessage() { return false }
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);
for (let tmr of tmrs) {
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" }
async onActorCreateOwned(actor, tete) {
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);
}

View File

@ -13,7 +13,7 @@ export class TrouNoir extends Draconique {
async onActorCreateOwned(actor, souffle) {
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);
}

File diff suppressed because one or more lines are too long

View File

@ -577,7 +577,7 @@
"Item": {
"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",
"musique", "chant", "danse", "jeu", "recettecuisine", "maladie", "poison", "oeuvre", "nourritureboisson" ],
"musique", "chant", "danse", "jeu", "recettecuisine", "maladie", "poison", "oeuvre", "nourritureboisson", "signedraconique" ],
"objet": {
"description": "",
"quantite": 1,
@ -868,6 +868,18 @@
"encombrement": 0,
"quantite": 1,
"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">
{{#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>
<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-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
</div>
@ -340,7 +340,7 @@
<ul class="item-list alterne-list">
{{#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>
<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-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
</div>
@ -351,7 +351,7 @@
<ul class="item-list alterne-list">
{{#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>
<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-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
</div>
@ -384,20 +384,28 @@
</li>
{{/if}}
<li class="item flexrow">
<span class="competence-label">Demi rêve :</span>
<span>
{{#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"/>
</span>
{{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}}
??
{{else}}
{{caseTmr-label data.reve.tmrpos.coord}}
{{data.reve.tmrpos.coord}}
{{/if}}
{{/if}}
</span>
{{/if}}
</li>
{{/if}}
<li class="item flexrow">
@ -424,13 +432,27 @@
</div>
<hr>
{{#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>
<ul class="item-list alterne-list">
{{#each sorts as |mysort key|}}
<li class="item list-item flexrow" data-item-id="{{mysort._id}}" data-attribute="{{key}}">
<span class="sort-label"> <a data-id="{{mysort._id}}">{{mysort.name}}</a></span>
<span>{{mysort.data.draconic}} / {{mysort.data.difficulte}}</span>
<div class="item-controls">
{{#each sorts as |sort key|}}
<li class="item list-item flexrow" data-item-id="{{sort._id}}" data-attribute="{{key}}">
<span class="display-label flex-grow"> <a data-item-id="{{sort._id}}">{{sort.name}}</a></span>
<span>{{sort.data.draconic}} / {{sort.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>
@ -440,9 +462,15 @@
<h3>Sorts en Réserve:</h3>
<ul class="item-list alterne-list">
{{#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}}" />
<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>
{{/each}}
</ul>
@ -451,8 +479,8 @@
<ul class="item-list">
{{#each meditations as |meditation 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>
<div class="item-controls">
<span class="meditation-label flex-grow"><a data-item-id="{{meditation._id}}">{{meditation.name}} - {{meditation.data.competence}}</a></span>
<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-delete" title="Supprimer"><i class="fas fa-trash"></i></a>
</div>
@ -466,8 +494,8 @@
<ul class="flex-group-left">
{{#each queues as |queue key|}}
<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>
<div class="item-controls">
<span class="display-label flex-grow"><a data-item-id="{{queue._id}}">{{queue.name}}</a></span>
<div class="item-controls flex-shrink">
<a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
</div>
</li>
@ -477,8 +505,8 @@
<ul class="item-list">
{{#each souffles as |souffle key|}}
<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>
<div class="item-controls">
<span class="display-label flex-grow"><a data-item-id="{{souffle._id}}">{{souffle.name}}</a></span>
<div class="item-controls flex-shrink">
<a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
</div>
</li>
@ -488,8 +516,8 @@
<ul class="item-list">
{{#each tetes as |tete key|}}
<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>
<div class="item-controls">
<span class="display-label flex-grow"><a data-item-id="{{tete._id}}">{{tete.name}}</a></span>
<div class="item-controls flex-shrink">
<a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
</div>
</li>
@ -499,8 +527,8 @@
<ul class="item-list">
{{#each ombres as |ombre key|}}
<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>
<div class="item-controls">
<span class="display-label flex-grow"><a data-item-id="{{ombre._id}}">{{ombre.name}}</a></span>
<div class="item-controls flex-shrink">
<a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
</div>
</li>
@ -512,8 +540,12 @@
<ul class="item-list">
{{#each hautreve.rencontres as |rencontre 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>
<div class="item-controls">
<span class="display-label flex-grow"><a data-item-id="{{key}}">{{rencontre.rencontre.name}} - {{rencontre.coord}}</a></span>
<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>
</div>
</li>
@ -523,11 +555,11 @@
<h3>Cases Spéciales:</h3>
<ul class="item-list">
{{#each hautreve.casesTmr as |casetmr key|}}
<li class="item" data-item-id="{{casetmr._id}}" data-attribute="{{key}}">
<span class="item-controls">
<li class="item flexrow" data-item-id="{{casetmr._id}}" data-attribute="{{key}}">
<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>
</span>
<span class="case-label"><a data-id="{{casetmr._id}}">{{casetmr.name}}</a></span>
</li>
{{/each}}
</ul>
@ -544,7 +576,7 @@
<span class="competence-title competence-label">{{piece.name}}</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>
<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-delete" title="Supprimer"><i class="fas fa-trash"></i></a>
</div>
@ -589,7 +621,7 @@
<li class="item flexrow list-item" data-actor-id="{{monture.id}}">
<img class="sheet-competence-img" src="{{monture.img}}" title="{{monture.name}}"/>
<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>
</div>
</li>
@ -604,7 +636,7 @@
<span class="competence-title subacteur-label"><a>{{vehicule.name}}</a></span>
<span class="competence-title">{{vehicule.categorie}}</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>
</div>
</li>
@ -617,7 +649,7 @@
<li class="item flexrow list-item" data-actor-id="{{suivant.id}}">
<img class="sheet-competence-img" src="{{suivant.img}}" title="{{suivant.name}}"/>
<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>
</div>
</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>
<div>
{{#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>.
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.
Vous apercevez un signe draconique éphémère, qu'il faut aller lire en <strong>{{meditation.data.tmr}}</strong>.
{{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}}
<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>

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">
<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">

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-right' src='systems/foundryvtt-reve-de-dragon/styles/img/ui/dir-bottom-right.svg'>
</div>
<div class="flex-group-center">
<a id="lancer-sort">Lancer un Sort</a>
<div class="flex-group-center lire-signe-draconique">
<a>Lire un signe draconique</a>
</div>
<div class="flex-group-center lancer-sort">
<a>Lancer un Sort</a>
</div>
<hr>
<div class="flex-group-center">

View File

@ -29,15 +29,15 @@
</div>
<div class="form-group">
<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 class="form-group">
<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 class="form-group">
<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 class="form-group">
<label for="xp">Niveau minimum</label>
@ -49,15 +49,15 @@
</div>
<div class="form-group">
<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 class="form-group">
<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 class="form-group item-cout">
<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 class="flexcol">
<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>