Compare commits

...

28 Commits

Author SHA1 Message Date
8aece9cad1 Fixes pour possession 2022-07-09 08:56:44 +02:00
ffd36a045e Merge pull request 'Quelques petits fixes' (#541) from VincentVk/foundryvtt-reve-de-dragon:v1.5 into v1.5
Reviewed-on: public/foundryvtt-reve-de-dragon#541
2022-07-09 08:55:48 +02:00
Vincent Vandemeulebrouck
bafc52a151 Fix: recherches incorrectes
* cas rare d'un personnage avec carac reve-actuel défini, mais sans
label, qui rend impossible de trouver une autre caractéristique, ce
qui empêche tout jet de caractéristique

* '/rdd <carac> <comp>', quand plusieurs compétences peuvent
correspondre, la première devrait être choisie... mais en pratique,
échec et rien ne se passe
2022-07-08 01:22:53 +02:00
Vincent Vandemeulebrouck
940baad04c Amélioration des possession
* messages plus clairs
* initiatives
* en cas de possession en cours, c'est la seule action possible
* accès dans le HUD
2022-07-03 15:32:24 +02:00
70c26ebfe0 Fix possession 2022-07-02 08:54:55 +02:00
782c6a8fe2 Merge pull request 'Fix possession' (#540) from VincentVk/foundryvtt-reve-de-dragon:v1.5 into v1.5
Reviewed-on: public/foundryvtt-reve-de-dragon#540
2022-07-02 08:53:30 +02:00
Vincent Vandemeulebrouck
b417fdfe32 Fix possession
On peut maintenant lutter pour les haut-rêvants
Les messages ont été clarifiés
2022-07-02 01:41:55 +02:00
11274c51d6 Add VincentVK fixes 2022-06-26 16:26:17 +02:00
6377964d07 Merge pull request 'Corrections des TMRs et météo' (#539) from VincentVk/foundryvtt-reve-de-dragon:v1.5-tmrs into v1.5
Reviewed-on: public/foundryvtt-reve-de-dragon#539
2022-06-26 16:23:58 +02:00
Vincent Vandemeulebrouck
8cf43d4e8a Fix Maîtrise avec TMR cachée
On ne donne plus le nom et les coordonées des cases à maîtriser
quand le personnage est perdu
2022-06-26 01:18:18 +02:00
Vincent Vandemeulebrouck
5efb7d9be0 Fix des TMRs visibles/cachées
Parfois on peut retrouver son chemin dans les TMR:

- Terre d'attache
- Connaisance du fleuve
- changeur des rêves vaincus

On ne peut pas utiliser un messager/passeur quand on est perdu

Les messages ne contiennent plus 'undefined' pour le changeur
2022-06-26 01:18:17 +02:00
Vincent Vandemeulebrouck
f54804c071 Fix checkSoufflePeage 2022-06-26 01:18:17 +02:00
Vincent Vandemeulebrouck
59ece09357 Possession pour non haut-rêvant 2022-06-26 01:18:17 +02:00
Vincent Vandemeulebrouck
5868bf16e0 Commande météo 2022-06-26 01:18:17 +02:00
6873cf0d41 Increase release 2022-06-26 01:17:56 +02:00
2c73f5aa11 Increase release 2022-06-06 23:18:33 +02:00
035da98aaa Merge pull request 'v1.5-fixes' (#538) from VincentVk/foundryvtt-reve-de-dragon:v1.5-fixes into v1.5
Reviewed-on: public/foundryvtt-reve-de-dragon#538
2022-06-06 23:17:23 +02:00
Vincent Vandemeulebrouck
2885ca1c8f Fix suppression messages combat 2022-06-06 23:03:09 +02:00
Vincent Vandemeulebrouck
218c88a924 Fix détérioration armure
Support des armures sous forme:

* entier
* 0
* d4, d4-1
* 1d4, 1d4-1

Détérioration diminuée de 10 (au lieu de remise à 0)

Décrémentation correcte de l'armure
2022-06-06 23:03:09 +02:00
Vincent Vandemeulebrouck
e22b6c52f1 Fix méditation
- augmentation du malus en cas d'échec particulier/total
- le malus affecte négativement la méditation
- en cas d'échec, aucun signe n'est créé
2022-06-06 23:03:09 +02:00
Vincent Vandemeulebrouck
9b8f694dda Réorganisation dans le haut-rêve
Ajout de la force des rencontres en attente
Ajout des cases pour les sorts et cases spéciales

1. Têtes; souffles et queues
2. Effets temporaires: signes, rencontres, sorts en réserve
3. Apprentissages: sorts, méditations
4. cases spéciales
2022-06-06 23:03:08 +02:00
Vincent Vandemeulebrouck
75562b0af8 Suppressions de logs 2022-06-06 23:03:08 +02:00
Vincent Vandemeulebrouck
3a684c3c54 Fix typo resaon 2022-06-06 23:03:08 +02:00
Vincent Vandemeulebrouck
70354abacb Fix XP en sort
Cas d'xp en sort concaténée
2022-06-06 23:03:08 +02:00
Vincent Vandemeulebrouck
bdead49d01 Renommage methode checkNull 2022-06-06 23:03:08 +02:00
60b6da5cd3 Merge pull request 'v1.5' (#1) from public/foundryvtt-reve-de-dragon:v1.5 into v1.5
Reviewed-on: #1
2022-06-06 23:03:02 +02:00
66218be14a Fix TMR 2022-06-06 23:03:02 +02:00
Vincent Vandemeulebrouck
9aad57c00c Fix Nom des TMR désolation
Il n'y a pas que la désolation de Demain

Change-Id: I41cef0204edae57d6071c8b3b33f0dd63a42c2a5
2022-06-06 23:03:02 +02:00
31 changed files with 837 additions and 587 deletions

View File

@@ -22,13 +22,6 @@ export class RdDActorEntiteSheet extends ActorSheet {
});
}
/* -------------------------------------------- */
_checkNull(items) {
if (items && items.length) {
return items;
}
return [];
}
/* -------------------------------------------- */
async getData() {

View File

@@ -94,7 +94,7 @@ export class RdDActorSheet extends ActorSheet {
RdDItemArme.computeNiveauArmes(formData.combat, formData.competences);
RdDItemArme.ajoutCorpsACorps(formData.combat, formData.competences, formData.data.carac);
formData.esquives = this.actor.getCompetences("Esquive").map(i => foundry.utils.deepClone(i.data));
formData.combat = RdDCombatManager.finalizeArmeList(formData.combat, formData.competences, formData.data.carac);
formData.combat = RdDCombatManager.listActionsArmes(formData.combat, formData.competences, formData.data.carac);
this.armesList = formData.combat;
@@ -315,7 +315,7 @@ export class RdDActorSheet extends ActorSheet {
// Boutons spéciaux MJs
html.find('.forcer-tmr-aleatoire').click(async event => {
this.actor.cacheTMRetMessage();
this.actor.reinsertionAleatoire("Action MJ");
});
html.find('.afficher-tmr').click(async event => {
this.actor.afficheTMRetMessage();
@@ -335,8 +335,8 @@ export class RdDActorSheet extends ActorSheet {
html.find('.arme-initiative a').click(async event => {
let combatant = game.combat.data.combatants.find(c => c.actor.data._id == this.actor.data._id);
if (combatant) {
let arme = this._getEventArmeCombat(event);
RdDCombatManager.rollInitiativeCompetence(combatant._id, arme);
let action = this._getEventArmeCombat(event);
RdDCombatManager.rollInitiativeAction(combatant._id, action);
} else {
ui.notifications.info("Impossible de lancer l'initiative sans être dans un combat.");
}

View File

@@ -25,14 +25,6 @@ export class RdDActorVehiculeSheet extends ActorSheet {
});
}
/* -------------------------------------------- */
_checkNull(items) {
if (items && items.length) {
return items;
}
return [];
}
/* -------------------------------------------- */
async getData() {
const objectData = Misc.data(this.object);

View File

@@ -372,12 +372,30 @@ export class RdDActor extends Actor {
const list = this.getDraconicList();
return duplicate(list[0]);
}
getDraconicOrZero() {
const list = this.getDraconicList().filter(it => Misc.data(it).data.niveau >= 0);
if (list.length == 0) {
return { name: "Aucun", data: { niveau: 0 } };
getDraconicOuPossession() {
const possessions = this.items.filter(it => Misc.data(it).type == 'competencecreature' && Misc.templateData(it).ispossession)
.sort(Misc.descending(it => Misc.templateData(it).niveau));
if (possessions.length>0) {
return duplicate(possessions[0]);
}
return duplicate(list[0]);
const draconics = this.getDraconicList().filter(it => Misc.data(it).data.niveau >= 0);
if (draconics.length> 0) {
return duplicate(draconics[0]);
}
return {
img: 'systems/foundryvtt-reve-de-dragon/icons/entites/possession.webp',
name: 'Sans draconic',
data: {
niveau: 0,
defaut_carac: "reve",
}
};
}
getPossession(possessionId) {
return this.items.find(it => it.type == 'possession' && it.data.data.possessionid == possessionId);
}
getPossessions() {
return this.items.filter(it => it.type == 'possession');
}
getDemiReve() {
@@ -783,7 +801,7 @@ export class RdDActor extends Actor {
async combattreReveDeDragon(force) {
let rollData = {
actor: this,
competence: duplicate(this.getDraconicOrZero()),
competence: duplicate(this.getDraconicOuPossession()),
canClose: false,
rencontre: duplicate(TMRRencontres.getRencontre('rdd')),
tmr: true,
@@ -1472,10 +1490,8 @@ export class RdDActor extends Actor {
isTMRCache() {
return this.data.data.reve.tmrpos.cache;
}
/* -------------------------------------------- */
async cacheTMRetMessage() {
await this.reinsertionAleatoire("Action MJ");
await this.cacheTMR();
notifyRefreshTMR() {
game.socket.emit(SYSTEM_SOCKET_ID, {
msg: "msg_tmr_move", data: {
actorId: this.data._id,
@@ -1487,27 +1503,27 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
async afficheTMRetMessage() {
await this.montreTMR();
game.socket.emit(SYSTEM_SOCKET_ID, {
msg: "msg_tmr_move", data: {
actorId: this.data._id,
tmrPos: this.data.data.reve.tmrpos
}
});
this.notifyRefreshTMR();
}
/* -------------------------------------------- */
async reinsertionAleatoire(raison) {
async reinsertionAleatoire(raison, accessible = tmr => true) {
const innaccessible = this.buildTMRInnaccessible();
let tmr = await TMRUtility.getTMRAleatoire(tmr => accessible(tmr) && !innaccessible.includes(tmr.coord));
ChatMessage.create({
content: `${raison} : ré-insertion aléatoire.`,
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name)
});
const innaccessible = this.buildTMRInnaccessible();
let tmr = await TMRUtility.getTMRAleatoire(tmr => !innaccessible.includes(tmr.coord));
this.updateCoordTMR(tmr.coord);
this.cacheTMR();
await this.forcerPositionTMRInconnue(tmr);
return tmr;
}
async forcerPositionTMRInconnue(tmr) {
await this.cacheTMR();
await this.updateCoordTMR(tmr.coord);
this.notifyRefreshTMR();
}
/* -------------------------------------------- */
buildTMRInnaccessible() {
const tmrInnaccessibles = this.filterItemsData(it => Draconique.isCaseTMR(it) &&
@@ -2403,7 +2419,7 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
async checkSoufflePeage(tmr) {
if ((tmr.type == 'pont' || tmr.type == 'cite') && EffetsDraconiques.isPeage(actor)) {
if ((tmr.type == 'pont' || tmr.type == 'cite') && EffetsDraconiques.isPeage(this)) {
await this.reveActuelIncDec(-1);
ChatMessage.create({
content: "Vous êtes sous le coup d'un Péage : l'entrée sur cette case vous a coûté 1 Point de Rêve (déduit automatiquement).",
@@ -2540,9 +2556,9 @@ export class RdDActor extends Actor {
if (rollData.competence.type == 'competencecreature') {
if (rollData.competence.data.iscombat) {
if (rollData.competence.data.ispossession) {
RdDPossession.managePossession(this, rollData.competence)
RdDPossession.onAttaquePossession(this, rollData.competence)
} else {
const arme = RdDItemCompetenceCreature.toArme(rollData.competence)
const arme = RdDItemCompetenceCreature.toActionArme(rollData.competence)
RdDCombat.createUsingTarget(this)?.attaque(competence, arme)
}
return
@@ -2568,8 +2584,8 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
conjurerPossession(possession) {
let draconic = this.getBestDraconic()
RdDPossession.managePossession(this, draconic, possession)
let draconic = this.getDraconicOuPossession();
RdDPossession.onAttaquePossession(this, draconic, possession)
}
/* -------------------------------------------- */
@@ -2838,20 +2854,19 @@ export class RdDActor extends Actor {
}
/* -------------------------------------------- */
async _meditationResult(meditationData) {
async _meditationResult(meditationRoll) {
this.santeIncDec("fatigue", 2);
const signeData = RdDItemSigneDraconique.prepareSigneDraconiqueMeditation(meditationData.meditation, meditationData.rolled)
if (signeData) {
await this.createEmbeddedDocuments("Item", [signeData]);
if (meditationRoll.rolled.isSuccess) {
await this.createEmbeddedDocuments("Item", [RdDItemSigneDraconique.prepareSigneDraconiqueMeditation(meditationRoll.meditation, meditationRoll.rolled)]);
}
await RdDResolutionTable.displayRollData(meditationData, this.name, 'chat-resultat-meditation.html');
await RdDResolutionTable.displayRollData(meditationRoll, this.name, 'chat-resultat-meditation.html');
}
/* -------------------------------------------- */
_meditationEPart(meditationData) {
this.updateEmbeddedDocuments('Item', [{ _id: meditationData._id, 'data.malus': meditationData.meditation.data.malus - 1 }]);
_meditationEPart(meditationRoll) {
this.updateEmbeddedDocuments('Item', [{ _id: meditationRoll.meditation._id, 'data.malus': meditationRoll.meditation.data.malus - 1 }]);
}
@@ -3133,7 +3148,7 @@ export class RdDActor extends Actor {
return carac.chance;
}
let entry = Misc.findFirstLike(name, Object.entries(carac), { mapper: it => it[1].label, description: 'caractéristique' });
return entry.length > 0 ? carac[entry[0]] : undefined;
return entry && entry.length > 0 ? carac[entry[0]] : undefined;
}
/* -------------------------------------------- */
@@ -3154,9 +3169,9 @@ export class RdDActor extends Actor {
}
/* -------------------------------------------- */
refreshTMRView(tmrData) {
refreshTMRView() {
if (this.currentTMR) {
this.currentTMR.externalRefresh(tmrData)
this.currentTMR.externalRefresh();
}
}
@@ -3209,7 +3224,7 @@ export class RdDActor extends Actor {
let competence = Misc.data(this.getCompetence(arme.data.competence));
if (arme || (competence.type == 'competencecreature' && competence.data.iscombat)) {
if (competence.data.ispossession) {
RdDPossession.managePossession(this, competence);
RdDPossession.onAttaquePossession(this, competence);
} else {
RdDCombat.createUsingTarget(this)?.attaque(competence, arme);
}
@@ -3278,11 +3293,11 @@ export class RdDActor extends Actor {
protection = Math.max(protection - penetration, 0);
protection += this.getProtectionNaturelle();
// Gestion des cas particuliers sur la fenêtre d'encaissement
if (attackerRoll.dmg.encaisserSpecial && attackerRoll.dmg.encaisserSpecial == "noarmure") {
if (attackerRoll.dmg.encaisserSpecial == "noarmure") {
protection = 0;
}
if (attackerRoll.dmg.encaisserSpecial && attackerRoll.dmg.encaisserSpecial == "chute" && Number(protection) > 2) {
protection = 2;
if (attackerRoll.dmg.encaisserSpecial == "chute") {
protection = Math.min(protection, 2);
}
console.log("Final protect", protection, attackerRoll);
return protection;
@@ -3290,20 +3305,25 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
_deteriorerArmure(item, dmg) {
if (!ReglesOptionelles.isUsing('deteriorationArmure')) {
let itemData = duplicate(Misc.data(item));
if (!ReglesOptionelles.isUsing('deteriorationArmure') || itemData.data.protection == '0') {
return;
}
let itemData = duplicate(Misc.data(item));
itemData.data.deterioration = (itemData.data.deterioration ?? 0) + dmg;
if (itemData.data.deterioration >= 10) {
itemData.data.deterioration = 0;
let res = /\d+/.exec(itemData.data.protection);
if (!res) {
itemData.data.protection = "1d" + itemData.data.protection;
itemData.data.deterioration -= 10;
let res = /(\d+)?d(\d+)(\-\d+)?/.exec(itemData.data.protection);
if (res) {
let malus = Misc.toInt(res[3]) - 1;
let armure = Misc.toInt(res[2]);
if (armure+malus <= 0){
itemData.data.protection = 0;
} else {
itemData.data.protection = '' + (res[1]??'1') + 'd' + armure + malus;
}
}
else if (res = /(\d+d\d+)(\-\d+)?/.exec(itemData.data.protection)) {
let malus = Misc.toInt(res[2]) - 1;
itemData.data.protection = res[1] + malus;
else if (/\d+/.exec(itemData.data.protection)) {
itemData.data.protection = "1d" + itemData.data.protection;
}
else {
ui.notifications.warn(`La valeur d'armure de votre ${item.name} est incorrecte`);

View File

@@ -30,7 +30,7 @@ export class RdDItemArme extends Item {
switch (armeData ? armeData.type : '') {
case 'arme': return armeData;
case 'competencecreature':
return RdDItemCompetenceCreature.toArme(armeData);
return RdDItemCompetenceCreature.toActionArme(armeData);
}
return RdDItemArme.mainsNues();
}
@@ -189,7 +189,7 @@ export class RdDItemArme extends Item {
categorie_parade: 'sans-armes'
}
};
mergeObject(corpsACorps.data, actorData ??{}, { overwrite: false });
mergeObject(corpsACorps.data, actorData ?? {}, { overwrite: false });
return corpsACorps;
}

View File

@@ -212,8 +212,11 @@ export class RdDItemCompetence extends Item {
/* -------------------------------------------- */
static findCompetence(list, idOrName, options = {}) {
if (idOrName == undefined) {
return undefined;
}
options = mergeObject(options, {
filter: it => RdDItemCompetence.isCompetence(it),
preFilter: it => RdDItemCompetence.isCompetence(it),
description: 'compétence',
});
return list.find(it => it.id == idOrName && RdDItemCompetence.isCompetence(it))

View File

@@ -11,14 +11,14 @@ export class RdDItemCompetenceCreature extends Item {
rollData.competence.data.categorie = "creature"
rollData.selectedCarac = rollData.carac.carac_creature
if (rollData.competence.data.iscombat) {
rollData.arme = RdDItemCompetenceCreature.toArme(rollData.competence);
rollData.arme = RdDItemCompetenceCreature.toActionArme(rollData.competence);
}
}
/* -------------------------------------------- */
static toArme(item) {
static toActionArme(item) {
if (RdDItemCompetenceCreature.isCompetenceAttaque(item)) {
// si c'est un Item compétence: cloner pour ne pas modifier lma compétence
// si c'est un Item compétence: cloner pour ne pas modifier la compétence
let arme = Misc.data( (item instanceof Item) ? item.clone(): item);
mergeObject(arme.data,
{
@@ -28,11 +28,12 @@ export class RdDItemCompetenceCreature extends Item {
dommagesReels: arme.data.dommages,
penetration: 0,
force: 0,
rapide: true
rapide: true,
action: 'attaque'
});
return arme;
}
console.error("RdDItemCompetenceCreature.toArme(", item, ") : impossible de transformer l'Item en arme");
console.error("RdDItemCompetenceCreature.toActionArme(", item, ") : impossible de transformer l'Item en arme");
return undefined;
}

View File

@@ -3,7 +3,7 @@ export class RdDItemMeditation {
static calculDifficulte(rollData) {
if (rollData.meditation) {
// Malus permanent éventuel
let diff = -rollData.meditation.data.malus ?? 0;
let diff = rollData.meditation.data.malus ?? 0;
if (!rollData.conditionMeditation.isHeure) diff -= 2;
if (!rollData.conditionMeditation.isVeture) diff -= 2;
if (!rollData.conditionMeditation.isComportement) diff -= 2;

View File

@@ -13,25 +13,24 @@ const tableSignesIndicatifs = [
]
const DIFFICULTE_LECTURE_SIGNE_MANQUE = +11;
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: [TMRUtility.typeTmrName(meditation.data.tmr)],
difficulte: RdDItemSigneDraconique.getDiffSigneMeditation(rolled.code),
ephemere: true,
duree: "1 round",
valeur: { "norm": 3, "sign": 5, "part": 10 }
}
};
}
return undefined;
meditation = Misc.data(meditation);
return {
name: "de la " + meditation.name,
type: "signedraconique",
img: meditation.img,
data: {
typesTMR: [TMRUtility.typeTmrName(meditation.data.tmr)],
difficulte: rolled.isSuccess ? RdDItemSigneDraconique.getDiffSigneMeditation(rolled.code) : DIFFICULTE_LECTURE_SIGNE_MANQUE,
ephemere: true,
duree: "1 round",
valeur: rolled.isSuccess ? { "norm": 3, "sign": 5, "part": 10 } : { "norm": 0, "sign": 0, "part": 0 }
}
};
}
static getDiffSigneMeditation(code) {
@@ -44,7 +43,7 @@ export class RdDItemSigneDraconique {
}
static getXpSortSigneDraconique(code, signe) {
return Misc.data(signe).data.valeur[code] ?? 0;
return Misc.toInt(Misc.data(signe).data.valeur[code] ?? 0);
}
static calculValeursXpSort(qualite, valeur, avant) {

View File

@@ -192,7 +192,7 @@ export class Misc {
if (!single) {
single = subset[0];
const choices = Misc.join(subset.map(it => options.mapper(it)), '<br>');
options.info(`Plusieurs choix de ${options.description}s possibles:<br>${choices}<br>Le premier sera choisi: ${mapToValue(single)}`);
options.onMessage(`Plusieurs choix de ${options.description}s possibles:<br>${choices}<br>Le premier sera choisi: ${options.mapper(single)}`);
}
return single;
}
@@ -211,7 +211,7 @@ export class Misc {
}
value = Grammar.toLowerCaseNoAccent(value);
const subset = elements.filter(options.preFilter)
.filter(it => Grammar.toLowerCaseNoAccent(options.mapper(it)).includes(value));
.filter(it => Grammar.toLowerCaseNoAccent(options.mapper(it))?.includes(value));
if (subset.length == 0) {
options.onMessage(`Pas de ${options.description} correspondant à ${value}`);
}

View File

@@ -1,5 +1,6 @@
import { ChatUtility } from "./chat-utility.js";
import { HIDE_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { Grammar } from "./grammar.js";
import { RdDItemArme } from "./item-arme.js";
import { RdDItemCompetence } from "./item-competence.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
@@ -26,7 +27,7 @@ const premierRoundInit = [
{ pattern: 'epeegnome', init: 5.35 },
{ pattern: 'masse', init: 5.30 },
{ pattern: 'gourdin', init: 5.25 },
{ pattern: 'fléau', init: 5.20 },
{ pattern: 'fleau', init: 5.20 },
{ pattern: 'dague', init: 5.15 },
{ pattern: 'autre', init: 5.10 },
];
@@ -84,28 +85,23 @@ export class RdDCombatManager extends Combat {
// calculate initiative
for (let cId = 0; cId < ids.length; cId++) {
const combatant = this.combatants.get(ids[cId]);
//if (!c) return results;
let rollFormula = formula; // Init per default
if (!rollFormula) {
let armeCombat, competence;
let rollFormula = formula ?? RdDCombatManager.formuleInitiative(2, 10, 0, 0);
if (!formula) {
if (combatant.actor.data.type == 'creature' || combatant.actor.data.type == 'entite') {
for (const competenceItemData of combatant.actor.data.items) {
if (competenceItemData.data.data.iscombat) {
competence = duplicate(competenceItemData);
}
const competence = combatant.actor.data.items.find(it => it.data.data.iscombat)
if (competence) {
rollFormula = RdDCombatManager.formuleInitiative(2, competence.data.carac_value, competence.data.niveau, 0);
}
rollFormula = "2+( (" + RdDCombatManager.calculInitiative(competence.data.niveau, competence.data.carac_value) + ")/100)";
} else {
for (const itemData of combatant.actor.data.items) {
if (itemData.type == "arme" && itemData.data.equipe) {
armeCombat = duplicate(itemData);
}
const armeCombat = combatant.actor.data.items.find(it => it.type == 'arme' && itemData.data.equipe)
const compName = (armeCombat == undefined) ? "Corps à corps" : armeCombat.data.competence;
const competence = RdDItemCompetence.findCompetence(combatant.actor.data.items, compName);
if (competence) {
const carac = combatant.actor.data.data.carac[competence.data.defaut_carac].value;
const niveau = competence.data.niveau;
const bonusEcaille = (armeCombat?.data.magique) ? armeCombat.data.ecaille_efficacite : 0;
rollFormula = RdDCombatManager.formuleInitiative(2, carac, niveau, bonusEcaille);
}
let compName = (armeCombat == undefined) ? "Corps à corps" : armeCombat.data.competence;
competence = RdDItemCompetence.findCompetence(combatant.actor.data.items, compName);
let bonusEcaille = (armeCombat && armeCombat.data.magique) ? armeCombat.data.ecaille_efficacite : 0;
rollFormula = "2+( (" + RdDCombatManager.calculInitiative(competence.data.niveau, Misc.data(combatant.actor).data.carac[competence.data.defaut_carac].value, bonusEcaille) + ")/100)";
}
}
//console.log("Combatat", c);
@@ -142,6 +138,10 @@ export class RdDCombatManager extends Combat {
return this;
};
static formuleInitiative(rang, carac, niveau, bonusMalus) {
return `${rang} +( (${RdDCombatManager.calculInitiative(niveau, carac, bonusMalus)} )/100)`;
}
/* -------------------------------------------- */
static calculInitiative(niveau, caracValue, bonusEcaille = 0) {
let base = niveau + Math.floor(caracValue / 2);
@@ -150,63 +150,77 @@ export class RdDCombatManager extends Combat {
}
/* -------------------------------------------- */
/** Retourne une liste triée d'armes avec le split arme1 main / arme 2 main */
static finalizeArmeList(armes, competences, carac) {
/** Retourne une liste triée d'actions d'armes avec le split arme1 main / arme 2 main */
static listActionsArmes(armes, competences, carac) {
// Gestion des armes 1/2 mains
let armesEquipe = [];
let actionsArme = [];
for (const arme of armes) {
let armeData = duplicate(Misc.data(arme));
if (armeData.data.equipe) {
let compData = competences.map(c => Misc.data(c)).find(c => c.name == armeData.data.competence);
let action = duplicate(Misc.data(arme));
if (action.data.equipe) {
let compData = competences.map(c => Misc.data(c)).find(c => c.name == action.data.competence);
armesEquipe.push(armeData);
armeData.data.dommagesReels = Number(armeData.data.dommages);
armeData.data.niveau = compData.data.niveau;
armeData.data.initiative = RdDCombatManager.calculInitiative(compData.data.niveau, carac[compData.data.defaut_carac].value);
actionsArme.push(action);
action.action = 'attaque';
action.data.dommagesReels = Number(action.data.dommages);
action.data.niveau = compData.data.niveau;
action.data.initiative = RdDCombatManager.calculInitiative(compData.data.niveau, carac[compData.data.defaut_carac].value);
// Dupliquer les armes pouvant être à 1 main et 2 mains en patchant la compétence
if (armeData.data.unemain && !armeData.data.deuxmains) {
armeData.data.mainInfo = "(1m)";
} else if (!armeData.data.unemain && armeData.data.deuxmains) {
armeData.data.mainInfo = "(2m)";
} else if (armeData.data.unemain && armeData.data.deuxmains) {
armeData.data.mainInfo = "(1m)";
if (action.data.unemain && !action.data.deuxmains) {
action.data.mainInfo = "(1m)";
} else if (!action.data.unemain && action.data.deuxmains) {
action.data.mainInfo = "(2m)";
} else if (action.data.unemain && action.data.deuxmains) {
action.data.mainInfo = "(1m)";
const comp2m = armeData.data.competence.replace(" 1 main", " 2 mains"); // Replace !
const comp2m = action.data.competence.replace(" 1 main", " 2 mains"); // Replace !
const comp = Misc.data(competences.find(c => c.name == comp2m));
const arme2main = duplicate(armeData);
const arme2main = duplicate(action);
arme2main.data.mainInfo = "(2m)";
arme2main.data.niveau = comp.data.niveau;
arme2main.data.competence = comp2m;
arme2main.data.initiative = RdDCombatManager.calculInitiative(arme2main.data.niveau, carac[comp.data.defaut_carac].value);
armesEquipe.push(arme2main);
const containsSlash = armeData.data.dommages.includes("/");
actionsArme.push(arme2main);
const containsSlash = action.data.dommages.includes("/");
if (containsSlash) {
const tableauDegats = armeData.data.dommages.split("/");
armeData.data.dommagesReels = Number(tableauDegats[0]);
const tableauDegats = action.data.dommages.split("/");
action.data.dommagesReels = Number(tableauDegats[0]);
arme2main.data.dommagesReels = Number(tableauDegats[1]);
}
else{
ui.notifications.info("Les dommages de l'arme à 1/2 mains " + armeData.name + " ne sont pas corrects (ie sous la forme X/Y)");
ui.notifications.info("Les dommages de l'arme à 1/2 mains " + action.name + " ne sont pas corrects (ie sous la forme X/Y)");
}
}
}
}
return armesEquipe.sort(Misc.ascending(armeData => armeData.name + (armeData.data.mainInfo ?? '')));
return actionsArme.sort(Misc.ascending(armeData => armeData.name + (armeData.data.mainInfo ?? '')));
}
static listActionsPossessions(actor) {
return RdDCombatManager._indexActions(actor.getPossessions().map(p =>
{
return {
name: p.name,
action: 'conjurer',
data: {
competence: p.name,
possessionid: p.data.data.possessionid,
}
}
}));
}
/* -------------------------------------------- */
static buildListeActionsCombat(combatant) {
if (combatant.actor == undefined) {
ui.notifications.warn(`Le combatant ${combatant.name} n'est pas associé à un acteur, impossible de déterminer ses actions de combat!`)
return [];
static listActionsCombat(combatant) {
const actor = combatant.actor;
let actions = RdDCombatManager.listActionsPossessions(actor);
if (actions.length>0) {
return actions;
}
const actorData = Misc.data(combatant.actor);
let items = combatant.actor.data.items;
let actions = []
if (combatant.actor.isCreature()) {
let items = actor.data.items;
if (actor.isCreature()) {
actions = actions.concat(items.filter(it => RdDItemCompetenceCreature.isCompetenceAttaque(it))
.map(competence => RdDItemCompetenceCreature.toArme(competence)));
.map(competence => RdDItemCompetenceCreature.toActionArme(competence)));
} else {
// Recupération des items 'arme'
let armes = items.filter(it => RdDItemArme.isArmeUtilisable(it))
@@ -214,14 +228,17 @@ export class RdDCombatManager extends Combat {
.concat(RdDItemArme.mainsNues());
let competences = items.filter(it => it.type == 'competence');
actions = actions.concat(RdDCombatManager.finalizeArmeList(armes, competences, actorData.data.carac));
actions = actions.concat(RdDCombatManager.listActionsArmes(armes, competences, actor.data.data.carac));
if (actorData.data.attributs.hautrevant.value) {
actions.push({ name: "Draconic", data: { initOnly: true, competence: "Draconic" } });
if (actor.data.data.attributs.hautrevant.value) {
actions.push({ name: "Draconic", action: 'haut-reve', data: { initOnly: true, competence: "Draconic" } });
}
}
actions.push({ name: "Autre action", data: { initOnly: true, competence: "Autre action" } });
return RdDCombatManager._indexActions(actions);
}
static _indexActions(actions) {
for (let index = 0; index < actions.length; index++) {
actions[index].index = index;
}
@@ -235,15 +252,15 @@ export class RdDCombatManager extends Combat {
let initMissing = game.combat.data.combatants.find(it => !it.initiative);
if (!initMissing) { // Premier round !
for (let combatant of game.combat.data.combatants) {
let arme = combatant.initiativeData?.arme;
let action = combatant.initiativeData?.arme;
//console.log("Parsed !!!", combatant, initDone, game.combat.current, arme);
if (arme && arme.type == "arme") {
if (action && action.type == "arme") {
for (let initData of premierRoundInit) {
if (arme.data.initpremierround.toLowerCase().includes(initData.pattern)) {
if (Grammar.toLowerCaseNoAccentNoSpace(action.data.initpremierround).includes(initData.pattern)) {
let msg = `<h4>L'initiative de ${combatant.actor.name} a été modifiée !</h4>
<hr>
<div>
Etant donné son ${arme.name}, son initative pour ce premier round est désormais de ${initData.init}.
Etant donné son ${action.name}, son initative pour ce premier round est désormais de ${initData.init}.
</div>`
ChatMessage.create({ content: msg });
game.combat.setInitiative(combatant._id, initData.init);
@@ -281,7 +298,7 @@ export class RdDCombatManager extends Combat {
].concat(options);
}
/* -------------------------------------------- */
static rollInitiativeCompetence(combatantId, arme) {
static rollInitiativeAction(combatantId, action) {
const combatant = game.combat.combatants.get(combatantId);
if (combatant.actor == undefined) {
ui.notifications.warn(`Le combatant ${combatant.name} n'est pas associé à un acteur, impossible de déterminer ses actions de combat!`)
@@ -299,34 +316,40 @@ export class RdDCombatManager extends Combat {
} else if (combatant.actor.getSurprise() == "demi") {
initOffset = 0;
initInfo = "Demi Surprise"
} else if (arme.name == "Autre action") {
} else if (action.action == 'conjurer') {
initOffset = 10;
caracForInit = combatant.actor.getReveActuel();
initInfo = "Possession"
} else if (action.name == 'autre') {
initOffset = 2;
initInfo = "Autre Action"
} else if (arme.name == "Draconic") {
} else if (action.action == 'haut-reve') {
initOffset = 9;
initInfo = "Draconic"
} else {
compData = Misc.data(RdDItemCompetence.findCompetence(combatant.actor.data.items, arme.data.competence));
compData = Misc.data(RdDItemCompetence.findCompetence(combatant.actor.data.items, action.data.competence));
compNiveau = compData.data.niveau;
initInfo = arme.name + " / " + arme.data.competence;
if (combatant.actor.data.type == 'creature' || combatant.actor.data.type == 'entite') {
caracForInit = compData.data.carac_value;
if (compData.data.categorie == "lancer") {
initOffset = 7;
}
else {
initOffset = 5;
}
} else {
caracForInit = Misc.data(combatant.actor).data.carac[compData.data.defaut_carac].value;
initOffset = RdDCombatManager._baseInitOffset(compData.data.categorie, arme);
initInfo = action.name + " / " + action.data.competence;
if (combatant.actor.data.type == 'creature' || combatant.actor.data.type == 'entite') {
caracForInit = compData.data.carac_value;
if (compData.data.categorie == "lancer") {
initOffset = 7;
}
else {
initOffset = 5;
}
} else {
caracForInit = Misc.data(combatant.actor).data.carac[compData.data.defaut_carac].value;
initOffset = RdDCombatManager._baseInitOffset(compData.data.categorie, action);
}
}
let malus = combatant.actor.getEtatGeneral(); // Prise en compte état général
// Cas des créatures et entités vs personnages
let rollFormula = initOffset + "+ ( (" + RdDCombatManager.calculInitiative(compNiveau, caracForInit) + " + " + malus + ") /100)";
let rollFormula = RdDCombatManager.formuleInitiative(initOffset, caracForInit, compNiveau, malus);
// Garder la trace de l'arme/compétence utilisée pour l'iniative
combatant.initiativeData = { arme: arme } // pour reclasser l'init au round 0
combatant.initiativeData = { arme: action } // pour reclasser l'init au round 0
game.combat.rollInitiative(combatantId, rollFormula, { initInfo: initInfo });
}
@@ -349,16 +372,21 @@ export class RdDCombatManager extends Combat {
static displayInitiativeMenu(html, combatantId) {
console.log("Combatant ; ", combatantId);
const combatant = game.combat.combatants.get(combatantId);
let armesList = RdDCombatManager.buildListeActionsCombat(combatant);
if (! (combatant?.actor) ) {
ui.notifications.warn(`Le combatant ${combatant.name ?? combatantId} n'est pas associé à un acteur, impossible de déterminer ses actions de combat!`)
return;
}
let actions = RdDCombatManager.listActionsCombat(combatant);
// Build the relevant submenu
if (armesList) {
if (actions) {
let menuItems = [];
for (let arme of armesList) {
for (let action of actions) {
menuItems.push({
name: arme.data.competence,
name: action.data.competence,
icon: "<i class='fas fa-dice-d6'></i>",
callback: target => { RdDCombatManager.rollInitiativeCompetence(combatantId, arme) }
callback: target => { RdDCombatManager.rollInitiativeAction(combatantId, action) }
});
}
new ContextMenu(html, ".directory-list", menuItems).render();
@@ -465,15 +493,15 @@ export class RdDCombat {
}
/* -------------------------------------------- */
static onMsgEncaisser(data) {
let defender = canvas.tokens.get(data.defenderTokenId).actor;
static onMsgEncaisser(msg) {
let defender = canvas.tokens.get(msg.defenderTokenId).actor;
if (Misc.isOwnerPlayerOrUniqueConnectedGM()) {
let attackerRoll = data.attackerRoll;
let attacker = data.attackerId ? game.actors.get(data.attackerId) : null;
let attackerRoll = msg.attackerRoll;
let attacker = msg.attackerId ? game.actors.get(msg.attackerId) : null;
defender.encaisserDommages(attackerRoll, attacker);
RdDCombat._deleteDefense(attackerRoll.passeArme);
RdDCombat._deleteAttaque(data.attackerId);
const rddCombat = RdDCombat.createForAttackerAndDefender(msg.attackerId, msg.defenderTokenId);
rddCombat?.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
}
}
@@ -482,11 +510,8 @@ export class RdDCombat {
let defenderToken = canvas.tokens.get(msg.defenderTokenId);
if (defenderToken && Misc.isUniqueConnectedGM()) {
const rddCombat = RdDCombat.createForAttackerAndDefender(msg.attackerId, msg.defenderTokenId);
if (rddCombat) {
const defenderRoll = msg.defenderRoll;
rddCombat.removeChatMessageActionsPasseArme(defenderRoll.passeArme);
rddCombat._chatMessageDefense(msg.paramChatDefense, msg.defenderRoll);
}
rddCombat?.removeChatMessageActionsPasseArme(msg.defenderRoll.passeArme);
rddCombat?._chatMessageDefense(msg.paramChatDefense, msg.defenderRoll);
}
}
@@ -1005,8 +1030,7 @@ export class RdDCombat {
await this.computeRecul(defenderRoll);
await this.computeDeteriorationArme(defenderRoll);
await RdDResolutionTable.displayRollData(defenderRoll, this.defender, 'chat-resultat-parade.html');
RdDCombat._deleteDefense(defenderRoll.passeArme);
this.removeChatMessageActionsPasseArme(defenderRoll.passeArme);
}
/* -------------------------------------------- */
@@ -1077,7 +1101,7 @@ export class RdDCombat {
async _onEsquiveNormale(defenderRoll) {
console.log("RdDCombat._onEsquiveNormal >>>", defenderRoll);
await RdDResolutionTable.displayRollData(defenderRoll, this.defender, 'chat-resultat-esquive.html');
RdDCombat._deleteDefense(defenderRoll.passeArme);
this.removeChatMessageActionsPasseArme(defenderRoll.passeArme);
}
/* -------------------------------------------- */
@@ -1217,7 +1241,6 @@ export class RdDCombat {
}
});
}
RdDCombat._deleteDefense(attackerRoll.passeArme);
this.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
}

View File

@@ -7,6 +7,7 @@ import { RdDItemCompetence } from "./item-competence.js";
import { Misc } from "./misc.js";
import { RdDCarac } from "./rdd-carac.js";
import { RdDDice } from "./rdd-dice.js";
import { RdDMeteo } from "./rdd-meteo.js";
import { RdDNameGen } from "./rdd-namegen.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDRollResolutionTable } from "./rdd-roll-resolution-table.js";
@@ -34,6 +35,7 @@ export class RdDCommands {
rddCommands.registerCommand({ path: ["/table", "souffle"], func: (content, msg, params) => RdDRollTables.getSouffle(true), descr: " Tire un Souffle de Dragon" });
rddCommands.registerCommand({ path: ["/table", "comp"], func: (content, msg, params) => RdDRollTables.getCompetence(true), descr: "Tire une compétence au hasard" });
rddCommands.registerCommand({ path: ["/table", "tarot"], func: (content, msg, params) => RdDRollTables.getTarot(true), descr: "Tire une carte du Tarot Draconique" });
rddCommands.registerCommand({ path: ["/meteo"], func: (content, msg, params) => rddCommands.getMeteo(msg, params), descr: "Propose une météo marine" });
rddCommands.registerCommand({ path: ["/nom"], func: (content, msg, params) => RdDNameGen.getName(msg, params), descr: "Génère un nom aléatoire" });
rddCommands.registerCommand({
@@ -274,9 +276,11 @@ export class RdDCommands {
diff = 0;
}
const caracName = params[0];
const compName = length > 1 ? Misc.join(params.slice(1, length), ' ') : undefined;
for (let actor of actors) {
await actor.rollCaracCompetence(caracName, compName, diff);
let competence = length > 1 ? actors[0].getCompetence(Misc.join(params.slice(1, length), ' ')) : undefined;
if (competence) {
for (let actor of actors) {
await actor.rollCaracCompetence(caracName, competence.name, diff);
}
}
return;
}
@@ -398,5 +402,8 @@ export class RdDCommands {
}
return true;
}
async getMeteo(msg, params) {
return await RdDMeteo.getMeteo();
}
}

134
module/rdd-meteo.js Normal file
View File

@@ -0,0 +1,134 @@
const vents = [
{ min: 0, max: 0, valeur: 'Calme' },
{ min: 1, max: 1, valeur: 'Légère brise' },
{ min: 2, max: 2, valeur: 'Jolie brise' },
{ min: 3, max: 3, valeur: 'Bonne brise' },
{ min: 4, max: 4, valeur: 'Vent frais' },
{ min: 5, max: 5, valeur: 'Coup de vent' },
{ min: 6, max: 6, valeur: 'Fort coup de vent' },
{ min: 7, max: 9, valeur: 'Tempête' },
{ min: 10, max: 13, valeur: 'Violente tempête' },
{ min: 14, valeur: 'Ouragan' },
]
const mers = [
{ min: 0, max: 0, valeur: 'Calme' },
{ min: 1, max: 1, valeur: 'Belle' },
{ min: 2, max: 2, valeur: 'Peu agitée' },
{ min: 3, max: 3, valeur: 'Agitée' },
{ min: 4, max: 4, valeur: 'Forte' },
{ min: 5, max: 6, valeur: 'Très forte' },
{ min: 7, max: 9, valeur: 'Grosse' },
{ min: 10, max: 13, valeur: 'Très grosse' },
{ min: 14, valeur: 'Énorme' },
]
const nuages = [
{ min: 0, max: 3, valeur: 'dégagé' },
{ min: 4, max: 6, valeur: 'passages nuageux' },
{ min: 7, max: 9, valeur: 'nuageux', },
{ min: 10, max: 10, valeur: 'brouillard' },
{ min: 11, max: 12, valeur: 'bruine' },
{ min: 13, valeur: 'très nuageux' },
]
const pluies = [
{ min: 0, max: 4, valeur: 'aucune' },
{ min: 5, max: 5, valeur: 'bruine, crachin, éparse' },
{ min: 6, max: 7, valeur: 'averses' },
{ min: 8, max: 10, valeur: 'pluvieux', },
{ min: 11, max: 13, valeur: 'forte pluie' },
{ min: 14, valeur: 'déluge' },
]
const temperatures = [
{ max: -14, valeur: 'glaciale' },
{ min: -13, max: -10, valeur: 'Très froide' },
{ min: -9, max: -7, valeur: 'froide' },
{ min: -6, max: -4, valeur: 'fraîche' },
{ min: -3, max: 3, valeur: 'de saison' },
{ min: 4, max: 6, valeur: 'élevée' },
{ min: 7, max: 9, valeur: 'chaude' },
{ min: 10, max: 13, valeur: 'torride' },
{ min: 14, valeur: 'caniculaire' },
]
export class RdDMeteo {
static async getForce() {
const roll = new Roll(`1dr`);
await roll.evaluate({ async: true });
return roll.total;
}
static async getPluie(nuage) {
return nuage <= 3 ? 0 : await RdDMeteo.getForce();
}
static async getTemperature() {
const degre = await RdDMeteo.getForce();
const rollChaudFroid = new Roll('1d2');
await rollChaudFroid.evaluate({ async: true });
const chaudFroid = rollChaudFroid.total == 1;
return chaudFroid.total ? degre : -degre;
}
static async getDirection(direction) {
const roll = new Roll(`1d16`);
await roll.evaluate({ async: true });
switch (roll.total % 16) {
case 0: return 'Nord';
case 1: return 'Nord Nord Est';
case 2: return 'Nord Est';
case 3: return 'Est Nord Est';
case 4: return 'Est';
case 5: return 'Est Sud Est';
case 6: return 'Sud Est';
case 7: return 'Sud Sud Est';
case 8: return 'Sud';
case 9: return 'Sud Sud Ouest';
case 10: return 'Sud Ouest';
case 11: return 'Ouest Sud Ouest';
case 12: return 'Ouest';
case 13: return 'Ouest Nord Ouest';
case 14: return 'Nord Ouest';
case 15: return 'Nord Nord Ouest';
}
return undefined;
}
static async getMeteo() {
const vent = await RdDMeteo.getForce();
const mer = await RdDMeteo.getForce();
const nuage = await RdDMeteo.getForce();
const pluie = await RdDMeteo.getPluie(nuage);
const temperature = await RdDMeteo.getTemperature();
const meteo = {
vent: { force: vent, direction: await RdDMeteo.getDirection(), },
mer: { force: mer, direction: await RdDMeteo.getDirection(), },
temperature: { force: temperature },
nuage: { force: nuage, },
pluie: { force: pluie },
}
meteo.vent.description = RdDMeteo.vent(meteo.vent.force);
meteo.mer.description = RdDMeteo.mer(meteo.mer.force),
meteo.temperature.description = RdDMeteo.temperature(meteo.temperature.force);
meteo.nuage.description = RdDMeteo.nuage(meteo.nuage.force);
meteo.pluie.description = RdDMeteo.pluie(meteo.pluie.force);
ChatMessage.create({
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-resultat-meteo.html', meteo),
whisper: ChatMessage.getWhisperRecipients('GM')
});
}
static description(liste, force, valeur = it => it.valeur) {
let select = liste.find(it => (it.min == undefined || it.min <= force) && (it.max == undefined || force <= it.max));
return valeur(select ?? liste[0]);
}
static vent(force) { return this.description(vents, force); }
static mer(force) { return this.description(mers, force); }
static nuage(force) { return this.description(nuages, force); }
static pluie(force) { return this.description(pluies, force); }
static temperature(force) { return this.description(temperatures, force); }
}

View File

@@ -14,44 +14,44 @@ Donc la compétence Possession ne peut être démarrée que par le MJ.
export class RdDPossession {
/* -------------------------------------------- */
static init() {
static init() {
}
/* -------------------------------------------- */
static searchPossessionFromEntite( attacker, defender) {
let poss = attacker.data.items.find( poss => poss.type == 'possession' && poss.data.data.possedeid == defender.data._id);
static searchPossessionFromEntite(attacker, defender) {
let poss = attacker.data.items.find(poss => poss.type == 'possession' && poss.data.data.possedeid == defender.data._id);
if (!poss) {
poss = defender.data.items.find( poss => poss.type == 'possession' && poss.data.data.possedeid == defender.data._id);
poss = defender.data.items.find(poss => poss.type == 'possession' && poss.data.data.possedeid == defender.data._id);
}
return poss && duplicate(poss) || undefined;
}
/* -------------------------------------------- */
static updateEtatPossession( possession ) {
static updateEtatPossession(possession) {
possession.ptsConjuration = 0
possession.ptsPossession = 0
console.log("Possession", possession)
if ( possession.data.compteur > 0) {
if (possession.data.compteur > 0) {
possession.ptsPossession = possession.data.compteur
}
if ( possession.data.compteur < 0) {
}
if (possession.data.compteur < 0) {
possession.ptsConjuration = Math.abs(possession.data.compteur)
}
}
possession.isPosseder = false
possession.isConjurer = false
if (possession.ptsPossession >= 2 ) {
if (possession.ptsPossession >= 2) {
possession.isPosseder = true
}
if (possession.ptsConjuration >= 2 ) {
if (possession.ptsConjuration >= 2) {
possession.isConjurer = true
}
}
/* -------------------------------------------- */
static async resultConjuration( rollData) {
static async resultConjuration(rollData) {
let actor = game.actors.get(rollData.possession.data.possedeid)
if ( !rollData.rolled.isSuccess ) {
if( rollData.isECNIDefender) {
if (!rollData.rolled.isSuccess) {
if (rollData.isECNIDefender) {
rollData.possession.data.compteur--
} else {
rollData.possession.data.compteur++
@@ -59,55 +59,41 @@ export class RdDPossession {
let update = { _id: rollData.possession._id, "data.compteur": rollData.possession.data.compteur }
await actor.updateEmbeddedDocuments('Item', [update])
}
this.updateEtatPossession(rollData.possession)
await RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-possession.html')
if ( rollData.possession.isPosseder || rollData.possession.isConjurer) {
if (rollData.possession.isPosseder || rollData.possession.isConjurer) {
actor.deleteEmbeddedDocuments("Item", [rollData.possession._id])
}
}
/* -------------------------------------------- */
static async onDefensePossession( attackerId, defenderId, possessionId) {
static async onDefensePossession(attackerId, defenderId, possessionId) {
let attacker = game.actors.get(attackerId)
let defender = game.actors.get(defenderId)
let possession = attacker.items.find( item => item.type =='possession' && item.data.data.possessionid == possessionId)
if ( !possession ) {
possession = defender.items.find( item => item.type =='possession' && item.data.data.possessionid == possessionId)
if ( !possession) {
ui.notifications.warn("Une erreur s'est produite : Aucune possession trouvée !!")
return
}
let possession = attacker.getPossession(possessionId) ?? defender.getPossession(possessionId) ;
if (!possession) {
ui.notifications.warn("Une erreur s'est produite : Aucune possession trouvée !!")
return
}
possession = duplicate(possession)
// Update for draconic roll
let rollData = {
possession: possession
mode: "conjuration",
isECNIDefender: defender.type == "entite",
possession: duplicate(possession),
attacker: attacker,
defender: defender,
competence: defender.getDraconicOuPossession(),
selectedCarac: defender.data.data.carac.reve,
forceCarac: { 'reve-actuel': { label: "Rêve Actuel", value: defender.getReveActuel() } }
}
rollData.actor = defender
if ( defender.type == "personnage") {
rollData.competence = duplicate(defender.getDraconicOrZero())
rollData.competence.data.defaut_carac = 'reve-actuel'
rollData.forceCarac = { 'reve-actuel': { label: "Rêve Actuel", value: defender.getReveActuel() } }
rollData.selectedCarac = defender.data.data.carac.reve
rollData.isECNIDefender = false
} else {
rollData.competence = duplicate(defender.getCompetence("Possession"))
rollData.competence.data.defaut_carac = "reve"
rollData.forceCarac = { 'reve': { label: "Rêve", value: defender.data.data.carac.reve.value } }
rollData.selectedCarac = defender.data.data.carac.reve
rollData.isECNIDefender = true
//RdDItemCompetenceCreature.setRollDataCreature( rollData )
}
rollData.mode = "conjuration"
rollData.possesseur = attacker.name
rollData.competence.data.defaut_carac = 'reve-actuel'
const dialog = await RdDRoll.create(defender, rollData,
{
html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-defense-possession.html',
options: { height: 400 }
options: { height: 450 }
},
{
name: 'conjurer',
@@ -121,54 +107,38 @@ export class RdDPossession {
}
/* -------------------------------------------- */
static async _onRollPossession( rollData, isSuccess ) {
let possession = rollData.possession
possession.isSuccess = isSuccess
this.updateEtatPossession( possession)
await RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-possession.html');
}
/* -------------------------------------------- */
static async managePossession(attacker, competence, possession=undefined) {
static async onAttaquePossession(attacker, competence, possession = undefined) {
const target = RdDCombat.getTarget()
if (target == undefined) {
ui.notifications.warn((game.user.targets?.size ?? 0) > 1
? "Vous devez choisir <strong>une seule</strong> cible à posséder!"
: "Vous devez choisir une cible à posséder!");
return;
}
const defender = target.actor
if ( !possession) {
possession = this.searchPossessionFromEntite( attacker, defender)
if ( !possession) {
possession = await this.createPossession(attacker, defender)
}
}
possession = duplicate(possession)
const defender = target.actor;
possession = duplicate(possession ?? this.searchPossessionFromEntite(attacker, defender) ??(await this.createPossession(attacker, defender)));
this.updateEtatPossession(possession)
let rollData = {
mode: "possession",
isECNIDefender: defender.type == "entite",
competence: competence,
possession: possession,
possede: defender.name,
possesseur: attacker.name,
attackerId: attacker.data._id,
defenderId: defender.data._id,
mode: "possession"
attacker: attacker,
defender: defender
};
if ( attacker.isCreature()) {
if (attacker.isCreature()) {
RdDItemCompetenceCreature.setRollDataCreature(rollData)
}
const dialog = await RdDRoll.create( attacker, rollData,
const dialog = await RdDRoll.create(attacker, rollData,
{
html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html',
options: { height: 540 }
}, {
name: 'jet-possession',
label: 'Possession: ',
label: rollData.isECNIDefender ? 'Conjurer la possession' : 'Possession',
callbacks: [
{ condition: r => (r.rolled.isSuccess), action: async r => await this._onRollPossession(r, true) },
{ condition: r => (r.rolled.isEchec), action: async r => await this._onRollPossession(r, false) },
@@ -178,7 +148,14 @@ export class RdDPossession {
}
/* -------------------------------------------- */
static async createPossession( attacker, defender ) {
static async _onRollPossession(rollData, isSuccess) {
rollData.possession.isSuccess = isSuccess;
this.updateEtatPossession(rollData.possession);
await RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-possession.html');
}
/* -------------------------------------------- */
static async createPossession(attacker, defender) {
let possessionData = {
name: "Possession en cours de " + attacker.name, type: 'possession',
img: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp",

View File

@@ -95,12 +95,15 @@ export class RdDTMRDialog extends Dialog {
createPixiSprites() {
EffetsDraconiques.carteTmr.createSprite(this.pixiTMR);
this.updateTokens();
this.demiReve = this._tokenDemiReve();
this._updateDemiReve();
this.forceDemiRevePositionView();
}
/* -------------------------------------------- */
_createTokens() {
if (!this.isDemiReveCache()){
this.demiReve = this._tokenDemiReve();
this._trackToken(this.demiReve);
}
let tokens = this._getTokensCasesTmr()
.concat(this._getTokensRencontres())
.concat(this._getTokensSortsReserve());
@@ -154,9 +157,9 @@ export class RdDTMRDialog extends Dialog {
return EffetsDraconiques.demiReve.token(this.pixiTMR, actorData, () => actorData.data.reve.tmrpos.coord);
}
_updateDemiReve() {
forceDemiRevePositionView() {
this.notifierResonanceSigneDraconique(this._getActorCoord());
this._setTokenPosition(this.demiReve);
this._trackToken(this.demiReve);
}
_getActorCoord() {
@@ -336,6 +339,10 @@ export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */
async choisirCasePortee(coord, portee) {
if (this.actor.isTMRCache())
{
return;
}
// Récupère la liste des cases à portées
let locList = TMRUtility.getTMRPortee(coord, portee);
this.colorierZoneRencontre(locList);
@@ -743,6 +750,7 @@ export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */
async _maitriserTMR(rollData, callbackMaitrise) {
this.minimize(); // Hide
rollData.isTMRCache = rollData.actor.isTMRCache();
const dialog = await RdDRoll.create(this.actor, rollData,
{
html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-maitrise-tmr.html',
@@ -874,49 +882,62 @@ export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */
async _onClickTMRPos(clickOddq) {
if (this.isDemiReveCache()) {
ui.notifications.error(`Vous ne connaissez plus votre position dans les TMR.
Vous devez utiliser les boutons de direction pour vous déplacer.
Une fois que vous aurez retrouvé votre demi-rêve, demandez au gardien de vérifier et rendre les TMR visibles.
`);
return;
}
let currentOddq = TMRUtility.coordTMRToOddq(this._getActorCoord());
console.log("deplacerDemiReve >>>>", currentOddq, clickOddq);
let targetCoord = TMRUtility.oddqToCoordTMR(clickOddq);
let currentCoord = TMRUtility.oddqToCoordTMR(currentOddq);
// Validation de la case de destination (gestion du cas des rencontres qui peuvent téléporter)
let deplacementType = this._calculDeplacement(targetCoord, currentCoord, currentOddq, clickOddq);
// Si le deplacement est valide
if (deplacementType == 'normal' || deplacementType == 'saut') {
await this._deplacerDemiReve(targetCoord, deplacementType);
} else if (deplacementType == 'messager') { // Dans ce cas, ouverture du lancement de sort sur la case visée
await this._messagerDemiReve(targetCoord);
} else {
ui.notifications.error("Vous ne pouvez pas vous déplacer que sur des cases adjacentes à votre position ou valides dans le cas d'une rencontre");
console.log("STATUS :", this.rencontreState, this.currentRencontre);
if (this.isDemiReveCache()) {
if (this.isTerreAttache(targetCoord)
|| (this.isCaseHumide(currentCoord) && this.isCaseHumide(targetCoord))
|| deplacementType == 'changeur')
{
// déplacement possible
await this.actor.montreTMR();
}
else
{
ui.notifications.error(`Vous ne connaissez plus votre position dans les TMR.
Vous devez utiliser les boutons de direction pour vous déplacer.
Une fois que vous aurez retrouvé votre demi-rêve, demandez au gardien de vérifier et rendre les TMR visibles.
`);
return;
}
}
switch (deplacementType){
case 'normal':
await this._deplacerDemiReve(targetCoord, deplacementType);
break;
case 'messager':
await this._messagerDemiReve(targetCoord);
break;
case 'changeur':
case 'passeur':
await this._deplacerDemiReve(targetCoord, deplacementType);
break;
default:
ui.notifications.error("Vous ne pouvez pas vous déplacer que sur des cases adjacentes à votre position ou valides dans le cas d'une rencontre");
console.log("STATUS :", this.rencontreState, this.currentRencontre);
}
this.checkQuitterTMR();
}
/* -------------------------------------------- */
_calculDeplacement(targetCoord, currentCoord, fromOddq, toOddq) {
const isInArea = this.rencontreState == 'aucune'
? (this.isTerreAttache(targetCoord) || this.isConnaissanceFleuve(currentCoord, targetCoord) || TMRUtility.distanceOddq(fromOddq, toOddq) <= 1)
: this.currentRencontre?.locList.find(coord => coord == targetCoord) ?? false
if (isInArea) {
switch (this.rencontreState) {
case 'aucune': return 'normal';
case 'messager': return 'messager';
case 'passeur': case 'changeur': return 'saut';
case 'passeur': case 'changeur': case 'messager': return this.rencontreState;
}
}
return 'erreur'
return 'erreur';
}
/* -------------------------------------------- */
@@ -932,9 +953,8 @@ export class RdDTMRDialog extends Dialog {
}
/* -------------------------------------------- */
externalRefresh(tmrData) {
externalRefresh() {
this.createPixiSprites();
this.forceDemiRevePositionView();
this.updateValuesDisplay();
this.updateTokens();
console.log("TMR REFRESHED !!!");
@@ -946,23 +966,17 @@ export class RdDTMRDialog extends Dialog {
this.nettoyerRencontre();
}
let tmr = TMRUtility.getTMR(targetCoord);
//console.log("deplacerDemiReve", tmr, this);
// Gestion cases spéciales type Trou noir, etc
tmr = await this.manageTmrInnaccessible(tmr);
await this.actor.updateCoordTMR(tmr.coord);
this._updateDemiReve();
this.forceDemiRevePositionView();
if (ReglesOptionelles.isUsing("appliquer-fatigue")) {
this.cumulFatigue += this.fatigueParCase;
}
this.updateValuesDisplay();
game.socket.emit(SYSTEM_SOCKET_ID, {
msg: "msg_tmr_move", data: {
actorId: this.actor.data._id,
tmrPos: Misc.data(this.actor).data.reve.tmrpos
}
});
this.actor.notifyRefreshTMR();
if (deplacementType == 'normal') { // Pas de rencontres après un saut de type passeur/changeur/...
await this.manageRencontre(tmr, () => this.postRencontre(tmr));
@@ -995,14 +1009,9 @@ export class RdDTMRDialog extends Dialog {
}
/* -------------------------------------------- */
async forceDemiRevePositionView() {
this._updateDemiReve();
}
/* -------------------------------------------- */
async forceDemiRevePosition(coord) {
async positionnerDemiReve(coord) {
await this.actor.updateCoordTMR(coord);
this._updateDemiReve();
this.forceDemiRevePositionView();
let tmr = TMRUtility.getTMR(coord);
await this.postRencontre(tmr);
return tmr;
@@ -1024,15 +1033,7 @@ export class RdDTMRDialog extends Dialog {
_getCaseRectangleCoord(coord) {
return this.pixiTMR.getCaseRectangle(TMRUtility.coordTMRToOddq(coord));
}
/* -------------------------------------------- */
_setTokenPosition(token) {
if (this.isDemiReveCache() && this.demiReve === token ) {
return;
}
this.pixiTMR.setPosition(token.sprite, TMRUtility.coordTMRToOddq(token.coordTMR()));
}
/* -------------------------------------------- */
_removeTokens(filter) {
const tokensToRemove = this.allTokens.filter(filter);
@@ -1040,10 +1041,13 @@ export class RdDTMRDialog extends Dialog {
this.pixiApp.stage.removeChild(token.sprite);
}
}
/* -------------------------------------------- */
_trackToken(token) {
if (this.demiReve === token && this.isDemiReveCache()) {
return;
}
this.pixiTMR.setPosition(token.sprite, TMRUtility.coordTMRToOddq(token.coordTMR()));
this.allTokens.push(token);
this._setTokenPosition(token);
}
}

View File

@@ -23,40 +23,63 @@ export class RdDTokenHud {
let token = canvas.tokens.get(tokenId);
let actor = token.actor;
let combatant = game.combat.combatants.find(c => Misc.data(c).tokenId == tokenId);
if (! (combatant?.actor) ) {
ui.notifications.warn(`Le combatant ${token.name} n'est pas associé à un acteur, impossible de déterminer ses actions de combat!`)
return;
}
app.hasExtension = true;
let armesList = RdDCombatManager.buildListeActionsCombat(combatant);
let actionsCombat = RdDCombatManager.listActionsCombat(combatant);
const hudData = {
combatant: combatant, armes: armesList,
commandes: [{ name: 'Initiative +1', command: 'inc', value: 0.01 }, { name: 'Initiative -1', command: 'dec', value: -0.01 }]
combatant: combatant,
actions: actionsCombat,
commandes: [
{ name: "Autre action", command: 'autre' },
{ name: 'Initiative +1', command: 'inc', value: 0.01 },
{ name: 'Initiative -1', command: 'dec', value: -0.01 }]
};
const controlIconCombat = html.find('.control-icon[data-action=combat]');
// initiative
await RdDTokenHud._configureSubMenu(controlIconCombat, 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-init.html', hudData,
await RdDTokenHud._configureSubMenu(controlIconCombat,
'systems/foundryvtt-reve-de-dragon/templates/hud-actor-init.html',
hudData,
(event) => {
let initCommand = event.currentTarget.attributes['data-command'].value;
let combatantId = event.currentTarget.attributes['data-combatant-id'].value;
if (!initCommand) {
let armeIndex = event.currentTarget.attributes['data-arme-id'].value;
let arme = armesList[armeIndex];
RdDCombatManager.rollInitiativeCompetence(combatantId, arme);
} else if (initCommand == 'inc') {
RdDCombatManager.incDecInit(combatantId, 0.01);
} else if (initCommand == 'dec') {
RdDCombatManager.incDecInit(combatantId, -0.01);
}
let initCommand = event.currentTarget.attributes['data-command']?.value;
let combatantId = event.currentTarget.attributes['data-combatant-id']?.value;
if (initCommand) {
RdDTokenHud._initiativeCommand(initCommand, combatantId);
} else {
let index = event.currentTarget.attributes['data-action-index'].value;
let action = actionsCombat[index];
RdDCombatManager.rollInitiativeAction(combatantId, action);
}
});
const controlIconTarget = html.find('.control-icon[data-action=target]');
// combat
await RdDTokenHud._configureSubMenu(controlIconTarget, 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-attaque.html', hudData,
(event) => {
let armeIndex = event.currentTarget.attributes['data-arme-id'].value;
actor.rollArme(armesList[armeIndex]);
const actionIndex = event.currentTarget.attributes['data-action-index']?.value;
const action = actionsCombat[actionIndex];
if (action.action == 'conjurer') {
actor.conjurerPossession(actor.getPossession(action.data.possessionid));
}
else {
actor.rollArme(action);
}
});
}
static _initiativeCommand(initCommand, combatantId) {
switch (initCommand) {
case 'inc': return RdDCombatManager.incDecInit(combatantId, 0.01);
case 'dec': return RdDCombatManager.incDecInit(combatantId, -0.01);
case 'autre': return RdDCombatManager.rollInitiativeAction(combatantId,
{ name: "Autre action", action: 'autre', data: { initOnly: true, competence: "Autre action" } });
}
}
/* -------------------------------------------- */
static async addTokenHudExtensions(app, html, tokenId) {
const controlIconCombat = html.find('.control-icon[data-action=combat]');

View File

@@ -221,8 +221,10 @@ export class RdDUtility {
];
Handlebars.registerHelper('upperFirst', str => Misc.upperFirst(str ?? 'Null'));
Handlebars.registerHelper('lowerFirst', str => Misc.lowerFirst(str ?? 'Null'));
Handlebars.registerHelper('upper', str => str?.toUpperCase() ?? 'NULL');
Handlebars.registerHelper('le', str => Grammar.articleDetermine(str));
Handlebars.registerHelper('apostrophe', (article, str) => Grammar.apostrophe(article, str));
Handlebars.registerHelper('un', str => Grammar.articleIndetermine(str));
Handlebars.registerHelper('accord', (genre, ...args) => Grammar.accord(genre, args));
Handlebars.registerHelper('buildConteneur', (objet) => { return new Handlebars.SafeString(RdDUtility.buildConteneur(objet)); });
@@ -326,8 +328,8 @@ export class RdDUtility {
}
/* -------------------------------------------- */
static checkNull(items) {
if (items && items.length) {
static arrayOrEmpty(items) {
if (items?.length) {
return items;
}
return [];
@@ -360,44 +362,44 @@ export class RdDUtility {
RdDUtility.filterEquipementParType(formData);
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']);
formData.tetes = this.checkNull(formData.itemsByType['tete']);
formData.taches = this.checkNull(formData.itemsByType['tache']);
formData.meditations = this.checkNull(formData.itemsByType['meditation']);
formData.chants = this.checkNull(formData.itemsByType['chant']);
formData.danses = this.checkNull(formData.itemsByType['danse']);
formData.musiques = this.checkNull(formData.itemsByType['musique']);
formData.oeuvres = this.checkNull(formData.itemsByType['oeuvre']);
formData.jeux = this.checkNull(formData.itemsByType['jeu']);
formData.sorts = this.arrayOrEmpty(formData.itemsByType['sort']);
formData.signesdraconiques = this.arrayOrEmpty(formData.itemsByType['signedraconique']);
formData.queues = this.arrayOrEmpty(formData.itemsByType['queue']);
formData.souffles = this.arrayOrEmpty(formData.itemsByType['souffle']);
formData.ombres = this.arrayOrEmpty(formData.itemsByType['ombre']);
formData.tetes = this.arrayOrEmpty(formData.itemsByType['tete']);
formData.taches = this.arrayOrEmpty(formData.itemsByType['tache']);
formData.meditations = this.arrayOrEmpty(formData.itemsByType['meditation']);
formData.chants = this.arrayOrEmpty(formData.itemsByType['chant']);
formData.danses = this.arrayOrEmpty(formData.itemsByType['danse']);
formData.musiques = this.arrayOrEmpty(formData.itemsByType['musique']);
formData.oeuvres = this.arrayOrEmpty(formData.itemsByType['oeuvre']);
formData.jeux = this.arrayOrEmpty(formData.itemsByType['jeu']);
formData.recettescuisine = this.checkNull(formData.itemsByType['recettecuisine']);
formData.recettesAlchimiques = this.checkNull(formData.itemsByType['recettealchimique']);
formData.maladies = this.checkNull(formData.itemsByType['maladie']);
formData.poisons = this.checkNull(formData.itemsByType['poison']);
formData.possessions = this.checkNull(formData.itemsByType['possession']);
formData.recettescuisine = this.arrayOrEmpty(formData.itemsByType['recettecuisine']);
formData.recettesAlchimiques = this.arrayOrEmpty(formData.itemsByType['recettealchimique']);
formData.maladies = this.arrayOrEmpty(formData.itemsByType['maladie']);
formData.poisons = this.arrayOrEmpty(formData.itemsByType['poison']);
formData.possessions = this.arrayOrEmpty(formData.itemsByType['possession']);
formData.maladiesPoisons = formData.maladies.concat(formData.poisons);
formData.competences = (formData.itemsByType.competence ?? []).concat(formData.itemsByType.competencecreature ?? []);
}
static filterEquipementParType(formData) {
formData.conteneurs = this.checkNull(formData.itemsByType['conteneur']);
formData.conteneurs = this.arrayOrEmpty(formData.itemsByType['conteneur']);
formData.materiel = this.checkNull(formData.itemsByType['objet']);
formData.armes = this.checkNull(formData.itemsByType['arme']);
formData.armures = this.checkNull(formData.itemsByType['armure']);
formData.munitions = this.checkNull(formData.itemsByType['munition']);
formData.livres = this.checkNull(formData.itemsByType['livre']);
formData.potions = this.checkNull(formData.itemsByType['potion']);
formData.ingredients = this.checkNull(formData.itemsByType['ingredient']);
formData.herbes = this.checkNull(formData.itemsByType['herbe']);
formData.monnaie = this.checkNull(formData.itemsByType['monnaie']);
formData.materiel = this.arrayOrEmpty(formData.itemsByType['objet']);
formData.armes = this.arrayOrEmpty(formData.itemsByType['arme']);
formData.armures = this.arrayOrEmpty(formData.itemsByType['armure']);
formData.munitions = this.arrayOrEmpty(formData.itemsByType['munition']);
formData.livres = this.arrayOrEmpty(formData.itemsByType['livre']);
formData.potions = this.arrayOrEmpty(formData.itemsByType['potion']);
formData.ingredients = this.arrayOrEmpty(formData.itemsByType['ingredient']);
formData.herbes = this.arrayOrEmpty(formData.itemsByType['herbe']);
formData.monnaie = this.arrayOrEmpty(formData.itemsByType['monnaie']);
formData.monnaie.sort(Monnaie.triValeurDenier());
formData.nourritureboissons = this.checkNull(formData.itemsByType['nourritureboisson']);
formData.gemmes = this.checkNull(formData.itemsByType['gemme']);
formData.nourritureboissons = this.arrayOrEmpty(formData.itemsByType['nourritureboisson']);
formData.gemmes = this.arrayOrEmpty(formData.itemsByType['gemme']);
formData.objets = formData.conteneurs
.concat(formData.materiel)
@@ -666,7 +668,7 @@ export class RdDUtility {
case "msg_tmr_move":
let actor = game.actors.get(sockmsg.data.actorId);
if (actor.isOwner || game.user.isGM) {
actor.refreshTMRView(sockmsg.data.tmrPos);
actor.refreshTMRView();
}
break;
}
@@ -681,7 +683,7 @@ export class RdDUtility {
let coord = event.currentTarget.attributes['data-tmr-coord'].value;
let actorId = event.currentTarget.attributes['data-actor-id'].value;
let actor = game.actors.get(actorId);
actor.tmrApp.forceDemiRevePosition(coord);
actor.tmrApp.positionnerDemiReve(coord);
});
// Gestion spécifique des sorts en réserve multiples (ie têtes)
html.on("click", '#sort-reserve', event => {
@@ -692,7 +694,7 @@ export class RdDUtility {
actor.tmrApp.lancerSortEnReserve(coord, sortId);
});
// gestion bouton tchat Acheter
// gestion bouton tchat Possession
html.on("click", '.defense-possession', event => {
let attackerId = event.currentTarget.attributes['data-attackerId'].value
let defenderId = event.currentTarget.attributes['data-defenderId'].value

View File

@@ -8,9 +8,14 @@ import { TMRType } from "./tmr-utility.js";
const typeRencontres = {
messager: {
msgSucces: (rencData) => `Le ${rencData.rencontre.name} vous propose d'emmener le message de votre un sort à ${rencData.rencontre.force} cases ${rencData.tmr.label}.`,
msgEchec: (rencData) => `Le ${rencData.rencontre.name} est pressé et continue son chemin d'une traite sans vous accorder un regard.`,
postSucces: (tmrDialog, rencData) => {
msgSucces: async (rencData) => {
if (rencData.actor.isTMRCache()){
return `Le ${rencData.rencontre.name} vous propose d'emmener le message de votre un sort, mais vous ne savez pas où vous êtes.`;
}
return `Le ${rencData.rencontre.name} vous propose d'emmener le message de votre un sort à ${rencData.rencontre.force} cases ${rencData.tmr.label}.`;
},
msgEchec: async (rencData)=> `Le ${rencData.rencontre.name} est pressé et continue son chemin d'une traite sans vous accorder un regard.`,
postSucces: async (tmrDialog, rencData) => {
tmrDialog.setStateRencontre(rencData.rencontre.type);
tmrDialog.choisirCasePortee(rencData.tmr.coord, rencData.rencontre.force);
},
@@ -28,9 +33,14 @@ const typeRencontres = {
},
passeur: {
msgSucces: (rencData) => `Le ${rencData.rencontre.name} vous propose de vous transporter à ${rencData.rencontre.force} cases des ${rencData.tmr.label}.`,
msgEchec: (rencData) => `Le prix que demande le ${rencData.rencontre.name} est trop élevé, vous êtes réduit à poursuivre votre chemin par vos propres moyens.`,
postSucces: (tmrDialog, rencData) => {
msgSucces: async (rencData) => {
if (rencData.actor.isTMRCache()){
return `Le ${rencData.rencontre.name} vous propose de vous transporter, mais vous ne savez pas où vous êtes.`;
}
return `Le ${rencData.rencontre.name} vous propose de vous transporter à ${rencData.rencontre.force} cases des ${rencData.tmr.label}.`;
},
msgEchec: async (rencData)=> `Le prix que demande le ${rencData.rencontre.name} est trop élevé, vous êtes réduit à poursuivre votre chemin par vos propres moyens.`,
postSucces: async (tmrDialog, rencData) => {
tmrDialog.setStateRencontre(rencData.rencontre.type);
tmrDialog.choisirCasePortee(rencData.tmr.coord, rencData.rencontre.force);
},
@@ -49,9 +59,9 @@ const typeRencontres = {
},
fleur: {
msgSucces: (rencData) => `Vous cueillez la ${rencData.rencontre.name}, son parfum vous apporte ${rencData.rencontre.force} points de Rêve.`,
msgEchec: (rencData) => `La ${rencData.rencontre.name} se fâne et disparaît entre vos doigts.`,
postSucces: (tmrDialog, rencData) => tmrDialog.actor.reveActuelIncDec(rencData.rencontre.force),
msgSucces: async (rencData) => `Vous cueillez la ${rencData.rencontre.name}, son parfum vous apporte ${rencData.rencontre.force} points de Rêve.`,
msgEchec: async (rencData)=> `La ${rencData.rencontre.name} se fâne et disparaît entre vos doigts.`,
postSucces: async (tmrDialog, rencData) => tmrDialog.actor.reveActuelIncDec(rencData.rencontre.force),
poesieSucces: {
reference: "L'Ennemi, Charles Baudelaire",
extrait: `Et qui sait si les fleurs nouvelles que je rêve
@@ -66,9 +76,9 @@ const typeRencontres = {
},
mangeur: {
msgSucces: (rencData) => `Le ${rencData.rencontre.name} claque de sa machoire dans le vide avant de fuir.`,
msgEchec: (rencData) => `Le ${rencData.rencontre.name} croque votre Rêve ! Il emporte ${rencData.rencontre.force} de vos points de rêve actuels`,
postEchec: (tmrDialog, rencData) => tmrDialog.actor.reveActuelIncDec(-rencData.rencontre.force),
msgSucces: async (rencData) => `Le ${rencData.rencontre.name} claque de sa machoire dans le vide avant de fuir.`,
msgEchec: async (rencData)=> `Le ${rencData.rencontre.name} croque votre Rêve ! Il emporte ${rencData.rencontre.force} de vos points de rêve actuels`,
postEchec: async (tmrDialog, rencData) => tmrDialog.actor.reveActuelIncDec(-rencData.rencontre.force),
poesieSucces: {
reference: "Conseil, Victor Hugo",
extrait: `Rois ! la bure est souvent jalouse du velours.
@@ -85,16 +95,17 @@ const typeRencontres = {
},
changeur: {
msgSucces: (rencData) => `Le ${rencData.rencontre.name} vaincu accepte de vous déplacer sur une autre ${TMRType[rencData.tmr.type].name} de votre choix en échange de sa liberté.`,
msgEchec: (rencData) => {
rencData.newTMR = TMRUtility.getTMRAleatoire(it => it.type = rencData.tmr.type);
return `Le ${rencData.rencontre.name} vous embobine avec des promesses, et vous transporte en ${rencData.newTMR.label} sans attendre votre avis.`;
},
postSucces: (tmrDialog, rencData) => {
msgSucces: async (rencData) => `Le ${rencData.rencontre.name} vaincu accepte de vous déplacer sur une autre ${TMRType[rencData.tmr.type].name} de votre choix en échange de sa liberté.`,
msgEchec: async (rencData) => `Le ${rencData.rencontre.name} vous embobine avec des promesses, et vous transporte sur une autre ${TMRType[rencData.tmr.type].name} sans attendre votre avis.`,
postSucces: async (tmrDialog, rencData) => {
tmrDialog.setStateRencontre(rencData.rencontre.type);
tmrDialog.choisirCaseType(rencData.tmr.type);
},
postEchec: (tmrDialog, rencData) => tmrDialog.forceDemiRevePosition(rencData.newTMR.coord),
postEchec: async (tmrDialog, rencData) => {
const newTMR = await TMRUtility.getTMRAleatoire(it => it.type == rencData.tmr.type && it.coord != rencData.tmr.coord);
await tmrDialog.actor.forcerPositionTMRInconnue(newTMR);
tmrDialog.positionnerDemiReve(newTMR.coord);
},
poesieSucces: {
reference: "Caligula - IIIème chant, Gérard de Nerval",
extrait: `Allez, que le caprice emporte
@@ -111,9 +122,9 @@ const typeRencontres = {
},
briseur: {
msgSucces: (rencData) => `Le ${rencData.rencontre.name} tente vainement de vous déconcentrer, avant de fuir sans demander son reste.`,
msgEchec: (rencData) => `Le ${rencData.rencontre.name} vous déconcentre au point de briser votre demi-rêve.`,
postEchec: (tmrDialog, rencData) => tmrDialog.close(),
msgSucces: async (rencData) => `Le ${rencData.rencontre.name} tente vainement de vous déconcentrer, avant de fuir sans demander son reste.`,
msgEchec: async (rencData)=> `Le ${rencData.rencontre.name} vous déconcentre au point de briser votre demi-rêve.`,
postEchec: async (tmrDialog, rencData) => tmrDialog.close(),
poesieSucces: {
reference: "Rêve de Dragon, Denis Gerfaud",
extrait: `La légende affirme que ce sont les Gnomes qui furent
@@ -134,8 +145,8 @@ const typeRencontres = {
},
reflet: {
msgSucces: (rencData) => `Le ${rencData.rencontre.name} s'estompe dans l'oubli.`,
msgEchec: (rencData) => `Vous êtes submergé par un ${rencData.rencontre.name}, les souvenirs vous retiennent tant qu'il ne sera pas vaincu!`,
msgSucces: async (rencData) => `Le ${rencData.rencontre.name} s'estompe dans l'oubli.`,
msgEchec: async (rencData)=> `Vous êtes submergé par un ${rencData.rencontre.name}, les souvenirs vous retiennent tant qu'il ne sera pas vaincu!`,
poesieSucces: {
reference: "Une charogne, Charles Baudelaire",
extrait: `Les formes s'effaçaient et n'étaient plus qu'un rêve,
@@ -152,9 +163,9 @@ const typeRencontres = {
},
passeurfou: {
msgSucces: (rencData) => `Le ${rencData.rencontre.name} tente vainement de découvrir où vous avez caché vos réserves. Vous le chassez, et en déroute il part harceler un autre voyageur du rêve.`,
msgEchec: (rencData) => TMRRencontres.msgEchecPasseurFou(rencData),
postEchec: (tmrDialog, rencData) => TMRRencontres.postEchecPasseurFou(tmrDialog, rencData),
msgSucces: async (rencData) => `Le ${rencData.rencontre.name} tente vainement de découvrir où vous avez caché vos réserves. Vous le chassez, et en déroute il part harceler un autre voyageur du rêve.`,
msgEchec: async (rencData)=> TMRRencontres.msgEchecPasseurFou(rencData),
postEchec: async (tmrDialog, rencData) => TMRRencontres.postEchecPasseurFou(tmrDialog, rencData),
poesieSucces: {
reference: "Un Fou et un Sage, Jean de La Fontaine",
extrait: `Certain Fou poursuivait à coups de pierre un Sage.
@@ -174,9 +185,9 @@ const typeRencontres = {
},
tbblanc: {
msgSucces: (rencData) => `Le ${rencData.rencontre.name} souleve une poussière blanche, vous tenez bon, et il tourbillonne en s'éloignant.`,
msgEchec: (rencData) => `Le souffle du ${rencData.rencontre.name} vous déstabilise et vous emmène dans un nuage de poussière.`,
postEchec: (tmrDialog, rencData) => TMRRencontres.onPostEchecTourbillon(tmrDialog, rencData, 1),
msgSucces: async (rencData) => `Le ${rencData.rencontre.name} souleve une poussière blanche, vous tenez bon, et il tourbillonne en s'éloignant.`,
msgEchec: async (rencData)=> `Le souffle du ${rencData.rencontre.name} vous déstabilise et vous emmène dans un nuage de poussière.`,
postEchec: async (tmrDialog, rencData) => TMRRencontres.onPostEchecTourbillon(tmrDialog, rencData, 1),
poesieSucces: {
reference: "Rêve de Dragon, Denis Gerfaud",
extrait: `Le Premier Âge fut appelé l'Âge des Dragons. Ce fut le commencement
@@ -191,9 +202,9 @@ const typeRencontres = {
},
tbnoir: {
msgSucces: (rencData) => `Le ${rencData.rencontre.name} orageux vous enveloppe de fureur et d'éclairs, vous tenez bon face à la tempête qui s'éloigne sans vous éloigner de votre chemin.`,
msgEchec: (rencData) => `Le ${rencData.rencontre.name} furieux vous secoue tel un fichu de paille malmené par les vents, et vous emporte dans la tourmente.`,
postEchec: (tmrDialog, rencData) => TMRRencontres.onPostEchecTourbillon(tmrDialog, rencData, 2),
msgSucces: async (rencData) => `Le ${rencData.rencontre.name} orageux vous enveloppe de fureur et d'éclairs, vous tenez bon face à la tempête qui s'éloigne sans vous éloigner de votre chemin.`,
msgEchec: async (rencData)=> `Le ${rencData.rencontre.name} furieux vous secoue tel un fichu de paille malmené par les vents, et vous emporte dans la tourmente.`,
postEchec: async (tmrDialog, rencData) => TMRRencontres.onPostEchecTourbillon(tmrDialog, rencData, 2),
poesieSucces: {
reference: "Rêve de Dragon, Denis Gerfaud",
extrait: `Car le Second Âge fut bel et bien celui des Magiciens. Durant cette période, les
@@ -207,9 +218,9 @@ const typeRencontres = {
},
tbrouge: {
msgSucces: (rencData) => `Le ${rencData.rencontre.name} s'abat avec violence mais vous êtes plus rapide et parvenez à lui échapper.`,
msgEchec: (rencData) => `Le ${rencData.rencontre.name} vous frappe de milliers de morsure et vous malmène à travers les terres médianes.`,
postEchec: (tmrDialog, rencData) => TMRRencontres.onPostEchecTourbillonRouge(tmrDialog, rencData),
msgSucces: async (rencData) => `Le ${rencData.rencontre.name} s'abat avec violence mais vous êtes plus rapide et parvenez à lui échapper.`,
msgEchec: async (rencData)=> `Le ${rencData.rencontre.name} vous frappe de milliers de morsure et vous malmène à travers les terres médianes.`,
postEchec: async (tmrDialog, rencData) => TMRRencontres.onPostEchecTourbillonRouge(tmrDialog, rencData),
poesieSucces: {
reference: "Qu'est-ce de votre vie ? une bouteille molle, Jean-Baptiste Chassignet",
extrait: `Qu'est-ce de votre vie ? un tourbillon rouant
@@ -228,10 +239,10 @@ const typeRencontres = {
},
rdd: {
msgSucces: (rencData) => `A tout seigneur, tout honneur, vous faites face à un ${rencData.rencontre.name}. Vous le maîtrisez et récupérez ses rêves. Vous gagnez ses ${rencData.rencontre.force} points de rêve`,
msgEchec: (rencData) => `A tout seigneur, tout honneur, vous faites face à un ${rencData.rencontre.name}. La rencontre tourne au cauchemar, dans la lutte épique, vous subissez ${rencData.rolled.isETotal ? 'deux queues' : 'une queue'} de dragon!`,
postSucces: (tmrDialog, rencData) => TMRRencontres.onPostSuccessReveDeDragon(tmrDialog, rencData),
postEchec: (tmrDialog, rencData) => TMRRencontres.onPostEchecReveDeDragon(tmrDialog, rencData),
msgSucces: async (rencData) => `A tout seigneur, tout honneur, vous faites face à un ${rencData.rencontre.name}. Vous le maîtrisez et récupérez ses rêves. Vous gagnez ses ${rencData.rencontre.force} points de rêve`,
msgEchec: async (rencData)=> `A tout seigneur, tout honneur, vous faites face à un ${rencData.rencontre.name}. La rencontre tourne au cauchemar, dans la lutte épique, vous subissez ${rencData.rolled.isETotal ? 'deux queues' : 'une queue'} de dragon!`,
postSucces: async (tmrDialog, rencData) => TMRRencontres.onPostSuccessReveDeDragon(tmrDialog, rencData),
postEchec: async (tmrDialog, rencData) => TMRRencontres.onPostEchecReveDeDragon(tmrDialog, rencData),
poesieSucces: {
reference: "Rêve de Dragon, Denis Gerfaud",
extrait: `Le monde est Rêve de Dragons, mais nous ne savons
@@ -404,7 +415,7 @@ export class TMRRencontres {
static async gererRencontre(tmrDialog, rencData) {
let gestion = TMRRencontres.getGestionRencontre(rencData.rencontre.type);
if (rencData.rolled.isSuccess) {
rencData.message = gestion.msgSucces(rencData);
rencData.message = await gestion.msgSucces(rencData);
if (rencData.nbRounds > 1) {
rencData.message += ` Au total, vous avez passé ${rencData.nbRounds} rounds à vous battre!`;
}
@@ -412,7 +423,7 @@ export class TMRRencontres {
return gestion.postSucces;
}
rencData.message = gestion.msgEchec(rencData);
rencData.message = await gestion.msgEchec(rencData);
if (rencData.nbRounds > 1) {
rencData.message += ` Vous avez passé ${rencData.nbRounds} rounds à lutter!`;
}
@@ -444,7 +455,7 @@ export class TMRRencontres {
if (tmrData.sortReserve) {
await tmrDialog.processSortReserve(tmrData.sortReserve);
}
await tmrDialog.forceDemiRevePosition(tmrData.newTMR.coord);
await tmrDialog.positionnerDemiReve(tmrData.newTMR.coord);
if (tmrData.sortReserve) {
tmrDialog.close();
}
@@ -469,7 +480,7 @@ export class TMRRencontres {
for (let i = 0; i < cases; i++) {
coord = await TMRUtility.deplaceTMRAleatoire(actor, coord).coord;
}
await tmrDialog.forceDemiRevePosition(coord)
await tmrDialog.positionnerDemiReve(coord)
}
/* -------------------------------------------- */

View File

@@ -94,9 +94,8 @@ export class Draconique {
token[type ?? this.code()] = linkData;
pixiTMR.addTooltip(token.sprite, this.tooltip(linkData));
return token;
return sprite;
}
/**
* factory d'élément graphique PIXI correpsondant à l'objet draconique
* @param {*} pixiTMR instance de PixiTMR qui gère les tooltips, les méthodes de création de sprite standard, les clicks.

View File

@@ -25,7 +25,7 @@ export class PixiTMR {
for (const [name, img] of Object.entries(PixiTMR.textures)) {
loader = loader.add(name, img);
}
loader.onLoad.add((error, resaon) => { console.log("ERROR", error, resaon) });
loader.onLoad.add((error, reason) => { console.log("ERROR", error, reason) });
loader.load( (loader, resources) => {
onLoad(loader, resources);
for (let onAnimate of this.callbacksOnAnimate) {

View File

@@ -29,7 +29,7 @@
"url": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/",
"license": "LICENSE.txt",
"flags": {},
"version": "1.5.77",
"version": "1.5.81",
"minimumCoreVersion": "0.8.0",
"compatibleCoreVersion": "9",
"scripts": [],
@@ -500,7 +500,7 @@
"dependencies": [],
"socket": true,
"manifest": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/v1.5/system.json",
"download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-1.5.77.zip",
"download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-1.5.81.zip",
"protected": false,
"gridDistance": 1,
"gridUnits": "m",

View File

@@ -55,7 +55,6 @@
{{/each}}
<li class="flexrow">
<span class="carac-label" name="carac-total">Total Caractéristiques</span>
{{log 'data-actor-creature' this}}
<span class="competence-value" name="carac-total-value">{{calc.caracTotal}}</span>
</li>
</ol>

View File

@@ -307,7 +307,6 @@
<a class="competence-label" name="{{esq.name}}">
<img class="sheet-competence-img" src="{{esq.img}}"/>
<span>{{esq.name}}</span>
{{log esq}}
</a>
</span>
<span class="arme-initiative"></span>
@@ -322,6 +321,7 @@
{{!-- Liste de blessures --}}
{{> "systems/foundryvtt-reve-de-dragon/templates/actor-liste-blessures-partial.html" this}}
{{#if maladiesPoisons.length}}
{{!-- Maladies & Poison --}}
<h3 class="blessures-title">Maladies & Poisons:</h3>
<ul class="item-list alterne-list">
@@ -355,28 +355,30 @@
</li>
{{/each}}
</ul>
{{/if}}
{{!-- Possession --}}
<h3 class="blessures-title">Possession:</h3>
<ul class="item-list alterne-list">
<li class="competence-header flexrow">
<span class="competence-title flex-grow competence-label">Nom</span>
<span class="competence-title competence-label">Type</span>
</li>
{{#if possessions.length}}
{{!-- Possession --}}
<h3 class="blessures-title">Possession:</h3>
<ul class="item-list alterne-list">
<li class="competence-header flexrow">
<span class="competence-title flex-grow competence-label">Nom</span>
<span class="competence-title competence-label">Type</span>
</li>
{{#each possessions as |possession key|}}
<li class="item flexrow list-item" data-item-id="{{possession._id}}">
<span class="competence-label">
<a class="sheet-possession-attack">{{possession.name}} (Conjurer)</a>
</span>
<span class="competence-label">{{possession.data.type}}</span>
<div class="item-controls">
<a class="item-control item-edit" title="Modifier"><i class="fas fa-edit"></i></a>
<a class="item-control item-delete" title="Supprimer"><i class="fas fa-trash"></i></a>
</div>
</li>
{{/each}}
</ul>
<li class="item flexrow list-item" data-item-id="{{possession._id}}">
<span class="competence-label">
<a class="sheet-possession-attack">{{possession.name}} (Conjurer)</a>
</span>
<span class="competence-label">{{possession.data.type}}</span>
<div class="item-controls">
<a class="item-control item-edit" title="Modifier"><i class="fas fa-edit"></i></a>
<a class="item-control item-delete" title="Supprimer"><i class="fas fa-trash"></i></a>
</div>
</li>
{{/each}}
</ul>
{{/if}}
</div>
{{!-- Connaissances Tab --}}
@@ -509,65 +511,8 @@
</ul>
</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 |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>
{{/each}}
</ul>
<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="{{reserve._id}}" data-attribute="{{key}}">
<img class="sheet-competence-img" src="{{reserve.sort.img}}" />
<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>
<h3>Méditations:</h3>
<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 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>
</li>
{{/each}}
</ul>
<hr>
{{/if}}
{{!-- Queues, Souffles, Tetes, Ombre --}}
{{#if queues.length}}
<h3>Queues:</h3>
<ul class="flex-group-left">
{{#each queues as |queue key|}}
@@ -579,28 +524,8 @@
</li>
{{/each}}
</ul>
<h3>Souffles:</h3>
<ul class="item-list">
{{#each souffles as |souffle key|}}
<li class="item flexrow" data-attribute={{key}} data-item-id="{{souffle._id}}">
<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>
{{/each}}
</ul>
<h3>Tetes:</h3>
<ul class="item-list">
{{#each tetes as |tete key|}}
<li class="item flexrow" data-attribute={{key}} data-item-id="{{tete._id}}">
<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>
{{/each}}
</ul>
{{/if}}
{{#if ombres.length}}
<h3>Ombres de Thanatos:</h3>
<ul class="item-list">
{{#each ombres as |ombre key|}}
@@ -612,35 +537,128 @@
</li>
{{/each}}
</ul>
{{/if}}
{{#if souffles.length}}
<h3>Souffles:</h3>
<ul class="item-list">
{{#each souffles as |souffle key|}}
<li class="item flexrow" data-attribute={{key}} data-item-id="{{souffle._id}}">
<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>
{{/each}}
</ul>
{{/if}}
{{#if tetes.length}}
<h3>Tetes:</h3>
<ul class="item-list">
{{#each tetes as |tete key|}}
<li class="item flexrow" data-attribute={{key}} data-item-id="{{tete._id}}">
<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>
{{/each}}
</ul>
{{/if}}
{{#if data.attributs.hautrevant.value}}
{{#if (and options.isGM signesdraconiques.length)}}
<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}}
{{#if hautreve.rencontres.length}}
<h3>Rencontres présentes:</h3>
<ul class="item-list">
{{#each hautreve.rencontres as |rencontre key|}}
<li class="item flexrow" data-item-id="{{key}}" data-attribute="{{key}}">
<span class="display-label"><a data-item-id="{{key}}">{{rencontre.name}} r{{rencontre.force}}</a></span>
<span class="flex-shrink">{{rencontre.coord}} - {{caseTmr-label rencontre.coord}}</span>
{{#if rencontre.date}}
<span>{{upperFirst rencontre.heure}}, le {{rencontre.date}}</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>
{{/each}}
</ul>
{{/if}}
{{#if hautreve.sortsReserve.length}}
<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="{{reserve._id}}" data-attribute="{{key}}">
<img class="sheet-competence-img" src="{{reserve.sort.img}}" />
<span class="display-label">{{reserve.sort.name}} r{{reserve.sort.data.ptreve_reel}}</span>
<span>{{reserve.coord}} - {{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>
{{/if}}
<hr>
<h3>Sorts:</h3>
<ul class="item-list alterne-list">
{{#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}}
- {{#if sort.data.caseTMRspeciale}}{{sort.data.caseTMRspeciale}}{{else}}{{upperFirst sort.data.caseTMR}}{{/if}}
</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>
{{/each}}
</ul>
<h3>Méditations:</h3>
<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 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>
</li>
{{/each}}
</ul>
<hr>
<h3>Rencontres présentes:</h3>
<ul class="item-list">
{{#each hautreve.rencontres as |rencontre key|}}
<li class="item flexrow" data-item-id="{{key}}" data-attribute="{{key}}">
<span class="display-label"><a data-item-id="{{key}}">{{rencontre.name}} - {{rencontre.coord}}</a></span>
<span class="flex-shrink">{{caseTmr-label rencontre.coord}}</span>
{{#if rencontre.date}}
<span>Le {{rencontre.date}} à {{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>
{{/each}}
</ul>
<hr>
<h3>Cases Spéciales:</h3>
<ul class="item-list">
{{#each hautreve.casesTmr as |casetmr key|}}
<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>
<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 hautreve.casesTmr}}
<h3>Cases Spéciales:</h3>
<ul class="item-list">
{{#each hautreve.casesTmr as |casetmr key|}}
<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>{{casetmr.data.coord}} - {{caseTmr-label casetmr.data.coord}}</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}}
<br><br>
{{/if}}
</div>

View File

@@ -1,6 +1,11 @@
<img class="chat-icon" src="{{competence.img}}" alt="{{competence.name}}"/>
<h4 data-categorie="tmr" data-actor-id="{{actor._id}}">
{{alias}} tente de {{maitrise.verbe}} {{le tmr.genre}} {{tmr.label}} ({{tmr.coord}})
{{alias}} tente de {{maitrise.verbe}} {{le tmr.genre}}
{{#if isTMRCache}}
{{caseTmr-type tmr.coord}}
{{else}}
{{tmr.label}} ({{tmr.coord}})
{{/if}}
</h4>
{{#if previous}}
{{#with previous}}
@@ -11,15 +16,20 @@
{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.html"}}
<hr>
<span>
{{#if rolled.isSuccess}}
{{alias}} parvient à {{maitrise.verbe}} {{le tmr.genre}} {{tmr.label}} !
{{alias}}
{{#if rolled.isSuccess}}parvient à{{else}}échoue à{{/if}}
{{maitrise.verbe}} {{le tmr.genre}}
{{#if isTMRCache}}
{{caseTmr-type tmr.coord}}
{{else}}
{{alias}} échoue à {{maitrise.verbe}} {{le tmr.genre}} {{tmr.label}}.
{{alias}} <strong>quitte les Terres Médianes</strong> !
{{#if souffle}}
<br>De plus, son échec total lui fait subir un Souffle de Dragon : {{souffle.name}}
{{tmr.label}} ({{tmr.coord}})
{{/if}}!
{{#if rolled.isEchec}}
{{alias}} <strong>quitte les Terres Médianes</strong> !
{{#if souffle}}
<br>De plus, son échec total lui fait subir un Souffle de Dragon : {{souffle.name}}
{{/if}}
{{/if}}
{{/if}}
</span>
{{#if poesie}}
<hr>

View File

@@ -0,0 +1,9 @@
<img class="chat-icon" src="icons/svg/lightning.svg" alt="Météo" />
<h4>Météo aléatoire</h4>
<ul>
<li>Vent: {{lowerFirst vent.description}} {{apostrophe 'de' vent.direction}}, force {{vent.force}}</li>
<li>Mer {{lowerFirst mer.description}}, {{apostrophe 'de' mer.direction}}, force {{mer.force}}</li>
<li>Température {{lowerFirst temperature.description}} ({{numberFormat temperature.force decimals=0 sign=true}})</li>
<li>Couverture nuageuse: {{lowerFirst nuage.description}}</li>
<li>Pluie: {{lowerFirst pluie.description}}</li>
</div>

View File

@@ -1,31 +1,38 @@
<img class="chat-icon" src="{{competence.img}}" />
<h4>
{{#if (eq mode "possession")}}
{{alias}} tente de posséder {{possede}}
{{attacker.name}} tente de {{#if isECNIDefender}}conjurer la possession de{{else}}posséder{{/if}} {{defender.name}}
{{else}}
{{alias}} tente de conjurer la possession de {{possesseur}}
{{defender.name}} tente de {{#if isECNIDefender}}résister à{{else}}conjurer la possession de{{/if}} {{attacker.name}}
{{/if}}
</h4>
{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.html"}}
<hr>
<div>
<span class='chat-card-button-area'>
<br>
{{#if (eq mode "possession")}}
{{#if possession.isSuccess}}
<a class='defense-possession chat-card-button' data-attackerId='{{attackerId}}'
data-defenderId='{{defenderId}}' data-possessionId='{{possession.data.possessionid}}'>Résister à la possession</a>
</a>
<a class='defense-possession chat-card-button'
data-attackerId='{{attacker.id}}'
data-defenderId='{{defender.id}}'
data-possessionId='{{possession.data.possessionid}}'>
{{#if isECNIDefender}}
Résister à la conjuration
{{else}}
Résister à la possession
{{/if}}
</a>
{{else}}
La Tentative de Possession a échouée !
La Tentative de {{#if isECNIDefender}}conjuration{{else}}possession{{/if}} a échoué !
{{/if}}
{{else}}
{{#if rolled.isSuccess}}
La Tentative de Possession a été conjurée ! {{alias}} résiste à la tentative de possession.
{{else}}
La Tentative de Possession n'a pas pu être conjurée !
La tentative de {{#if isECNIDefender}}conjuration a été repoussée{{else}}possession a été conjurée{{/if}}!
{{defender.name}} a résisté.
{{else}}
La tentative de {{#if isECNIDefender}}conjuration a réussi{{else}}possession n'a pas pu être conjurée{{/if}}!
{{/if}}
{{/if}}
<br>Points de Possession: {{possession.ptsPossession}}

View File

@@ -1,5 +1,9 @@
<form class="skill-roll-dialog">
<h2>Conjuration d'une Possession {{possession.name}}!</h2>
<h2>
{{defender.name}} tente de
{{#if isECNIDefender}}maintenir{{else}}résister à{{/if}}
la possession de {{attacker.name}}
</h2>
<div class="grid grid-2col">
<div class="flex-group-left">
<img class="chat-icon" src="{{competence.img}}" alt="{{competence.name}}"/>

View File

@@ -1,5 +1,10 @@
<form class="skill-roll-dialog">
<h2>Maîtrise {{tmr.label}} ({{tmr.coord}})</h2>
<h2>Maîtrise {{#if isTMRCache}}
{{tmr.type}}
{{else}}
{{tmr.label}} ({{tmr.coord}})
{{/if}}
</h2>
<div class="grid grid-2col">
<div class="flex-group-left">
<img class="chat-icon" src="{{competence.img}}" alt="{{competence.name}}"/>

View File

@@ -1,4 +1,3 @@
{{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">

View File

@@ -1,10 +1,13 @@
<div class="control-icon rdd-combat ">
<img class="rdd-hud-togglebutton" src="systems/foundryvtt-reve-de-dragon/icons/heures/hd06.svg" width="36" height="36" title="Attaque"/>
<div class="rdd-hud-list tokenhudext left">
{{#each armes as |arme key|}}
{{#unless arme.data.initOnly}}
<div class="control-icon tokenhudicon rdd-hud-menu rdd-attaque" data-combatant-id="{{../combatant.id}}" data-arme-id="{{arme.index}}" title="{{arme.name}}">
<label>C:{{arme.name}} {{arme.data.mainInfo}}</label>
{{#each actions as |action key|}}
{{#unless action.data.initOnly}}
<div class="control-icon tokenhudicon rdd-hud-menu rdd-attaque"
data-combatant-id="{{../combatant.id}}"
data-action-index="{{action.index}}"
title="{{action.name}}">
<label>{{action.name}} {{action.data.mainInfo}}</label>
</div>
{{/unless}}
{{/each}}

View File

@@ -1,14 +1,22 @@
<div class="control-icon rdd-initiative ">
<img class="rdd-hud-togglebutton" src="icons/svg/sword.svg" width="36" height="36" title="Initiative" />
<div class="rdd-hud-list tokenhudext right">
{{#each armes as |arme key|}}
<div class="control-icon tokenhudicon rdd-hud-menu" data-command="{{arme.command}}" data-combatant-id="{{../combatant.id}}" data-arme-id="{{arme.index}}" title="{{arme.name}}">
<label>I:{{arme.name}} {{arme.data.mainInfo}}</label>
{{#each actions as |action key|}}
{{log 'action-hud-init' action}}
<div class="control-icon tokenhudicon rdd-hud-menu"
data-combatant-id="{{../combatant.id}}"
data-action-index="{{action.index}}"
title="{{action.name}}">
<label>init: {{action.name}} {{action.data.mainInfo}}</label>
</div>
{{/each}}
{{#each commandes as |commande key|}}
<div class="control-icon tokenhudicon rdd-hud-menu" data-command="{{commande.command}}" data-combatant-id="{{../combatant.id}}" data-arme-id="{{commande.index}}" title="{{commande.name}}">
<label>I:{{commande.name}}</label>
<div class="control-icon tokenhudicon rdd-hud-menu"
data-command="{{commande.command}}"
data-combatant-id="{{../combatant.id}}"
data-action-index="{{commande.index}}"
title="{{commande.name}}">
<label>{{commande.name}}</label>
</div>
{{/each}}
</div>