diff --git a/module/actor-sheet.js b/module/actor-sheet.js
index a9fcc32e..29170dc2 100644
--- a/module/actor-sheet.js
+++ b/module/actor-sheet.js
@@ -62,9 +62,6 @@ export class RdDActorSheet extends ActorSheet {
if (this.actor.data.type == 'creature') return formData; // Shortcut
- // toujours avoir une liste d'armes (pour mettre esquive et corps à corps)
- formData.itemsByType.arme = formData.itemsByType.arme ?? [];
-
formData.competenceByCategory = Misc.classify(formData.data.competences, item => item.data.categorie);
formData.calc = {
@@ -93,38 +90,15 @@ export class RdDActorSheet extends ActorSheet {
});
- // Force empty arme, at least for Esquive
- if (formData.itemsByType.arme == undefined) formData.itemsByType.arme = [];
- for (const arme of formData.itemsByType.arme) {
- arme.data.niveau = 0; // Per default, TODO to be fixed
- for (const melee of formData.competenceByCategory.melee) {
- if (melee.name == arme.data.competence)
- arme.data.niveau = melee.data.niveau
- }
- for (const tir of formData.competenceByCategory.tir) {
- if (tir.name == arme.data.competence)
- arme.data.niveau = tir.data.niveau
- }
- for (const lancer of formData.competenceByCategory.lancer) {
- if (lancer.name == arme.data.competence)
- arme.data.niveau = lancer.data.niveau
- }
- }
-
- // To avoid armour and so on...
- formData.data.combat = duplicate(RdDUtility.checkNull(formData.itemsByType['arme']));
+ // toujours avoir une liste d'armes (pour mettre esquive et corps à corps)
+ formData.data.combat = duplicate(formData.itemsByType.arme ?? []);
+ RdDItemArme.computeNiveauArmes(formData.data.combat, formData.data.competences);
+ RdDItemArme.ajoutCorpsACorps(formData.data.combat, formData.data.competences, formData.data.carac );
+ formData.esquive = RdDItemCompetence.getEsquive(formData.data.competences);
formData.data.combat = RdDCombatManager.finalizeArmeList(formData.data.combat, formData.itemsByType.competence, formData.data.carac);
- formData.esquive = { name: "Esquive", niveau: formData.competenceByCategory?.melee.find(it => it.name == 'Esquive')?.data.niveau ?? -6 };
- let corpsACorps = formData.competenceByCategory?.melee.find(it => it.name == 'Corps à corps');
- if (corpsACorps) {
- let cc_init = RdDCombatManager.calculInitiative(corpsACorps.data.niveau, formData.data.carac['melee'].value);
- formData.data.combat.push(RdDItemArme.mainsNues({ niveau: corpsACorps.data.niveau, initiative: cc_init }));
- }
- this.armesList = duplicate(formData.data.combat);
- formData.data.carac.taille.isTaille = true; // To avoid button link;
- formData.data.blessures.resume = this.actor.computeResumeBlessure(formData.data.blessures);
+ this.armesList = formData.data.combat;
// Mise à jour de l'encombrement total et du prix de l'équipement
@@ -140,14 +114,18 @@ export class RdDActorSheet extends ActorSheet {
html: "
" + RdDUtility.makeHTMLfatigueMatrix(formData.data.sante.fatigue.value, formData.data.sante.endurance.max).html() + "
"
}
- RdDUtility.filterItemsPerTypeForSheet(formData);
- formData.data.sortReserve = formData.data.reve.reserve.list;
- formData.data.rencontres = duplicate(formData.data.reve.rencontre.list);
- formData.data.caseSpeciales = formData.itemsByType['casetmr'];
+ formData.hautreve = {
+ sortsReserve: formData.data.reve.reserve.list,
+ rencontres: duplicate(formData.data.reve.rencontre.list),
+ casesTmr: formData.itemsByType.casetmr
+ }
+
RdDUtility.buildArbreDeConteneur(this, formData);
- formData.data.vehiculesList = this.actor.buildVehiculesList();
- formData.data.monturesList = this.actor.buildMonturesList();
- formData.data.suivantsList = this.actor.buildSuivantsList();
+ formData.subacteurs = {
+ vehicules: this.actor.listeVehicules(),
+ montures: this.actor.listeMontures(),
+ suivants: this.actor.listeSuivants()
+ }
return formData;
}
diff --git a/module/actor.js b/module/actor.js
index 8b046d36..ee1e39af 100644
--- a/module/actor.js
+++ b/module/actor.js
@@ -311,6 +311,9 @@ export class RdDActor extends Actor {
}
return duplicate(list[0]);
}
+ getDemiReve() {
+ return this.data.data.reve.tmrpos.coord;
+ }
/* -------------------------------------------- */
async deleteSortReserve(sortReserve) {
let reserve = duplicate(this.data.data.reve.reserve);
@@ -1160,26 +1163,6 @@ export class RdDActor extends Actor {
return tmrInnaccessibles.map(it => it.data.coord);
}
- /* -------------------------------------------- */
- displayTMRQueueSouffleInformation() {
- let messages = [];
- for (let item of this.data.items) {
- if (EffetsDraconiques.isUrgenceDraconique(item)) {
- messages.push("Vous souffrez d'une Urgence Draconique : " + item.data.description);
- }
- if (EffetsDraconiques.isPeriple(item)) {
- messages.push("Vous souffrez du Souffle Périple. Vous devez gérer manuellement le détail du Périple.
" + item.data.description);
- }
- }
-
- if (messages.length > 0) {
- ChatMessage.create({
- whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
- content: "RAPPEL !
" + messages.join('
')
- });
- }
- }
-
/* -------------------------------------------- */
getTMRRencontres() {
return this.data.data.reve.rencontre;
@@ -1193,7 +1176,7 @@ export class RdDActor extends Actor {
//console.log("List", rencontres, len);
let newTable = [];
for (i = 0; i < len; i++) {
- if (rencontres.list[i].coord != this.data.data.reve.tmrpos.coord)
+ if (rencontres.list[i].coord != this.getDemiReve())
newTable.push(rencontres.list[i]);
}
if (newTable.length != len) {
@@ -1210,7 +1193,7 @@ export class RdDActor extends Actor {
let i = 0;
let already = false;
for (i = 0; i < len; i++) {
- if (rencontres.list[i].coord == this.data.data.reve.tmrpos.coord)
+ if (rencontres.list[i].coord == this.getDemiReve())
already = true;
}
if (!already) {
@@ -1232,9 +1215,7 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
async updateCoordTMR(coord) {
- let tmrPos = duplicate(this.data.data.reve.tmrpos);
- tmrPos.coord = coord;
- await this.update({ "data.reve.tmrpos": tmrPos });
+ await this.update({ "data.reve.tmrpos.coord": coord });
}
/* -------------------------------------------- */
@@ -2546,7 +2527,7 @@ export class RdDActor extends Actor {
let competence = this.getCompetence(compName);
if (arme || armeName || (competence.type == 'competencecreature' && competence.data.iscombat)) {
- RdDCombat.createUsingTarget(this).attaque(competence, arme);
+ RdDCombat.createUsingTarget(this)?.attaque(competence, arme);
} else {
this.rollCompetence(competence.name);
}
@@ -3007,7 +2988,7 @@ export class RdDActor extends Actor {
}
/* -------------------------------------------- */
- buildVehiculesList() {
+ listeVehicules() {
return this._buildActorLinksList(
this.data.data.subacteurs?.vehicules ?? [],
vehicle => {
@@ -3019,12 +3000,12 @@ export class RdDActor extends Actor {
}
/* -------------------------------------------- */
- buildSuivantsList() {
+ listeSuivants() {
return this._buildActorLinksList(this.data.data.subacteurs?.suivants ?? []);
}
/* -------------------------------------------- */
- buildMonturesList() {
+ listeMontures() {
return this._buildActorLinksList(this.data.data.subacteurs?.montures ?? []);
}
@@ -3205,6 +3186,9 @@ export class RdDActor extends Actor {
case 'souffle':
await this.onDeleteOwnedDraconique(item, options, id);
break;
+ case 'casetmr':
+ await this.onDeleteOwnedCaseTmr(item, options, id);
+ break;
}
}
@@ -3226,6 +3210,13 @@ export class RdDActor extends Actor {
}
}
+ async onDeleteOwnedCaseTmr(item, options, id) {
+ let draconique = Draconique.all().find(it => it.isCase(item));
+ if (draconique) {
+ draconique.onActorDeleteCaseTmr(this, item)
+ }
+ }
+
notifyGestionTeteSouffleQueue(item, manualMessage = true) {
ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
diff --git a/module/item-arme.js b/module/item-arme.js
index fa3428a5..0d6ea65d 100644
--- a/module/item-arme.js
+++ b/module/item-arme.js
@@ -1,4 +1,5 @@
import { RdDItemCompetenceCreature } from "./item-competencecreature.js"
+import { RdDCombatManager } from "./rdd-combat.js";
const nomCategorieParade = {
"sans-armes": "Sans arme / armes naturelles",
@@ -30,6 +31,17 @@ export class RdDItemArme extends Item {
return RdDItemArme.mainsNues();
}
+ static computeNiveauArmes(armes, competences) {
+ for (const arme of armes) {
+ arme.data.niveau = RdDItemArme.niveauCompetenceArme(arme, competences);
+ }
+ }
+
+ static niveauCompetenceArme(arme, competences) {
+ const compArme = competences.find(it => it.name == arme.data.competence);
+ return compArme?.data.niveau ?? -8;
+ }
+
/* -------------------------------------------- */
static getNomCategorieParade(arme) {
const categorie = arme?.data ? RdDItemArme.getCategorieParade(arme) : arme;
@@ -38,7 +50,7 @@ export class RdDItemArme extends Item {
/* -------------------------------------------- */
static needArmeResist(armeAttaque, armeParade) {
- if (!armeAttaque || !armeParade){
+ if (!armeAttaque || !armeParade) {
return false;
}
// Epées parant une arme de bois (cf. page 115 ), une résistance est nécessaire
@@ -54,7 +66,7 @@ export class RdDItemArme extends Item {
return arme.data.categorie_parade;
}
// pour compatibilité avec des personnages existants
- if (arme.type == 'competencecreature' || arme.data.categorie == 'creature' ) {
+ if (arme.type == 'competencecreature' || arme.data.categorie == 'creature') {
return arme.data.categorie_parade || (arme.data.isparade ? 'sans-armes' : '');
}
if (!arme.type.match(/arme|competencecreature/)) {
@@ -86,7 +98,7 @@ export class RdDItemArme extends Item {
/* -------------------------------------------- */
static needParadeSignificative(armeAttaque, armeParade) {
- if (!armeAttaque || !armeParade){
+ if (!armeAttaque || !armeParade) {
return false;
}
// categories d'armes à la parade (cf. page 115 )
@@ -145,10 +157,16 @@ export class RdDItemArme extends Item {
}
static isArmeUtilisable(item) {
- return item.type == 'arme' && item.data.equipe && (item.data.resistance > 0 || item.data.portee_courte>0);
+ return item.type == 'arme' && item.data.equipe && (item.data.resistance > 0 || item.data.portee_courte > 0);
}
- static mainsNues(actorData={}) {
+ static ajoutCorpsACorps(armes, competences, carac) {
+ let corpsACorps = competences.find(it => it.name == 'Corps à corps') ?? { data: { niveau: -6 } };
+ let init = RdDCombatManager.calculInitiative(corpsACorps.data.niveau, carac['melee'].value);
+ armes.push(RdDItemArme.mainsNues({ niveau: corpsACorps.data.niveau, initiative: init }));
+ }
+
+ static mainsNues(actorData = {}) {
const mainsNues = {
name: 'Mains nues',
data: {
@@ -163,8 +181,8 @@ export class RdDItemArme extends Item {
}
};
if (actorData) {
- mergeObject( mainsNues.data, actorData, {overwrite:false});
+ mergeObject(mainsNues.data, actorData, { overwrite: false });
}
return mainsNues
}
-}
+}
diff --git a/module/item-competence.js b/module/item-competence.js
index 2f947f17..c7be84c7 100644
--- a/module/item-competence.js
+++ b/module/item-competence.js
@@ -56,11 +56,15 @@ export class RdDItemCompetence extends Item {
return categorieCompetences[category].label;
}
+ static getEsquive(competences) {
+ return { name: 'Esquive', niveau: RdDItemCompetence.findCompetence(competences, 'Esquive')?.data.niveau ?? -6 };
+ }
+
/* -------------------------------------------- */
static isCompetenceArme(competence) {
switch (competence.data.categorie) {
case 'melee':
- return competence.name.toLowerCase() != 'esquive';
+ return competence.name != 'Esquive';
case 'tir':
case 'lancer':
return true;
diff --git a/module/rdd-combat.js b/module/rdd-combat.js
index db85f5c1..e668de44 100644
--- a/module/rdd-combat.js
+++ b/module/rdd-combat.js
@@ -413,9 +413,11 @@ export class RdDCombat {
? "Vous devez choisir une seule cible à attaquer!"
: "Vous devez choisir une cible à attaquer!");
}
- const defender = target?.actor;
- const defenderTokenId = target?.data._id;
- return this.create(attacker, defender, defenderTokenId, target)
+ else {
+ const defender = target?.actor;
+ const defenderTokenId = target?.data._id;
+ return this.create(attacker, defender, defenderTokenId, target)
+ }
}
/* -------------------------------------------- */
@@ -500,11 +502,13 @@ export class RdDCombat {
}
if ((game.user.isGM && !defenderToken.actor.hasPlayerOwner) || (defenderToken.actor.hasPlayerOwner && (game.user.character._id == defenderToken.actor.data._id))) {
const rddCombat = RdDCombat.createForAttackerAndDefender(msg.attackerId, msg.defenderTokenId);
- const defenderRoll = msg.defenderRoll;
- RdDCombat._storeAttaque(msg.attackerId, defenderRoll.attackerRoll);
- RdDCombat._storeDefense(defenderRoll);
- rddCombat.removeChatMessageActionsPasseArme(defenderRoll.passeArme);
- rddCombat._chatMessageDefense(msg.paramChatDefense);
+ if (rddCombat) {
+ const defenderRoll = msg.defenderRoll;
+ RdDCombat._storeAttaque(msg.attackerId, defenderRoll.attackerRoll);
+ RdDCombat._storeDefense(defenderRoll);
+ rddCombat.removeChatMessageActionsPasseArme(defenderRoll.passeArme);
+ rddCombat._chatMessageDefense(msg.paramChatDefense);
+ }
}
}
}
@@ -533,9 +537,11 @@ export class RdDCombat {
const rddCombat = RdDCombat.createForAttackerAndDefender(
event.currentTarget.attributes['data-attackerId']?.value,
event.currentTarget.attributes['data-defenderTokenId']?.value);
+ if (rddCombat) {
- rddCombat.onEvent(button, event);
- event.preventDefault();
+ rddCombat.onEvent(button, event);
+ event.preventDefault();
+ }
});
}
html.on("click", '#chat-jet-vie', event => {
diff --git a/module/rdd-commands.js b/module/rdd-commands.js
index 317b62bf..dddfdb2c 100644
--- a/module/rdd-commands.js
+++ b/module/rdd-commands.js
@@ -24,6 +24,8 @@ export class RdDCommands {
rddCommands.registerCommand({ path: ["/aide"], func: (content, msg, params) => rddCommands.help(msg), descr: "Affiche l'aide pour toutes les commandes" });
rddCommands.registerCommand({ path: ["/help"], func: (content, msg, params) => rddCommands.help(msg), descr: "Affiche l'aide pour toutes les commandes" });
rddCommands.registerCommand({ path: ["/table", "queues"], func: (content, msg, params) => RdDRollTables.getQueue(true), descr: "Tire une Queue de Dragon" });
+ rddCommands.registerCommand({ path: ["/table", "ideefixe"], func: (content, msg, params) => RdDRollTables.getIdeeFixe(true), descr: "Tire une Idée fixe" });
+ rddCommands.registerCommand({ path: ["/table", "desir"], func: (content, msg, params) => RdDRollTables.getDesirLancinant(true), descr: "Tire un Désir Lancinant" });
rddCommands.registerCommand({ path: ["/table", "ombre"], func: (content, msg, params) => RdDRollTables.getOmbre(true), descr: "Tire une Ombre de Dragon" });
rddCommands.registerCommand({ path: ["/table", "tetehr"], func: (content, msg, params) => RdDRollTables.getTeteHR(true), descr: "Tire une Tête de Dragon pour Hauts Revants" });
rddCommands.registerCommand({ path: ["/table", "tete"], func: (content, msg, params) => RdDRollTables.getTete(true), descr: "Tire une Tête de Dragon" });
diff --git a/module/rdd-rolltables.js b/module/rdd-rolltables.js
index 957c130a..74d06152 100644
--- a/module/rdd-rolltables.js
+++ b/module/rdd-rolltables.js
@@ -48,14 +48,22 @@ export class RdDRollTables {
static async getQueue(toChat = false) {
let queue = await RdDRollTables.drawItemFromRollTable("Queues de dragon", toChat);
if (queue.name.toLowerCase().includes('lancinant') ) {
- queue = await RdDRollTables.drawItemFromRollTable("Désirs lancinants", toChat);
+ return await RdDRollTables.getDesirLancinant(toChat);
}
if (queue.name.toLowerCase().includes('fixe') ) {
- queue = await RdDRollTables.drawItemFromRollTable("Idées fixes", toChat);
+ return await RdDRollTables.getIdeeFixe(toChat);
}
return queue;
}
+ static async getDesirLancinant(toChat = false) {
+ return await RdDRollTables.drawItemFromRollTable("Désirs lancinants", toChat);
+ }
+
+ static async getIdeeFixe(toChat = false) {
+ return await RdDRollTables.drawItemFromRollTable("Idées fixes", toChat);
+ }
+
/* -------------------------------------------- */
static async getTeteHR(toChat = false) {
return await RdDRollTables.drawItemFromRollTable("Têtes de Dragon pour haut-rêvants", toChat);
diff --git a/module/rdd-tmr-dialog.js b/module/rdd-tmr-dialog.js
index a3bcff7e..cbc1aafe 100644
--- a/module/rdd-tmr-dialog.js
+++ b/module/rdd-tmr-dialog.js
@@ -108,6 +108,11 @@ export class RdDTMRDialog extends Dialog {
this._createTokens();
}
+ removeToken(tmr, casetmr) {
+ this._removeTokens(t => t.coordTMR() == tmr.coord && t.caseSpeciale?._id == casetmr._id);
+ this.updateTokens()
+ }
+
/* -------------------------------------------- */
_getTokensCasesTmr() {
return this.casesSpeciales.map(c => this._tokenCaseSpeciale(c)).filter(token => token);
@@ -142,7 +147,7 @@ export class RdDTMRDialog extends Dialog {
async activateListeners(html) {
super.activateListeners(html);
- document.getElementById("tmrrow1").insertCell(1).append(this.pixiApp.view);
+ document.getElementById("tmrrow1").insertCell(0).append(this.pixiApp.view);
if (this.viewOnly) {
html.find('#lancer-sort').remove();
@@ -168,7 +173,6 @@ export class RdDTMRDialog extends Dialog {
let tmr = TMRUtility.getTMR(this.actor.data.data.reve.tmrpos.coord);
await this.manageRencontre(tmr, () => {
this.postRencontre(tmr);
- this.actor.displayTMRQueueSouffleInformation();
});
}
@@ -498,9 +502,7 @@ export class RdDTMRDialog extends Dialog {
}
async _resultatMaitriseCaseHumide(rollData) {
- if (rollData.rolled.isETotal) {
- rollData.souffle = await this.actor.ajouterSouffle({ chat: false });
- }
+ await this.souffleSiEchecTotal(rollData);
this.toclose = rollData.rolled.isEchec;
if (rollData.rolled.isSuccess && rollData.double) {
rollData.previous = { rolled: rollData.rolled, ajustements: rollData.ajustements };
@@ -518,6 +520,12 @@ export class RdDTMRDialog extends Dialog {
}
}
+ async souffleSiEchecTotal(rollData) {
+ if (rollData.rolled.isETotal) {
+ rollData.souffle = await this.actor.ajouterSouffle({ chat: false });
+ }
+ }
+
/* -------------------------------------------- */
isCaseHumide(tmr) {
if (!(TMRUtility.isCaseHumide(tmr) || this.isCaseHumideAdditionelle(tmr))) {
@@ -558,16 +566,29 @@ export class RdDTMRDialog extends Dialog {
await this._conquerir(tmr, {
difficulte: -9,
action: 'Conquérir la cité',
- onConqueteReussie: r => EffetsDraconiques.fermetureCites.onConquete(r.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr)),
- onConqueteEchec: r => this.close(),
+ onConqueteReussie: r => EffetsDraconiques.fermetureCites.onVisiteSupprimer(r.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr)),
+ onConqueteEchec: r => {
+ this.souffleSiEchecTotal(rollData);
+ this.close()
+ },
canClose: false
});
}
}
-
- removeToken(tmr, casetmr) {
- this._removeTokens(t => t.coordTMR() == tmr.coord && t.caseSpeciale?._id == casetmr._id);
- this.updateTokens()
+ /* -------------------------------------------- */
+ async purifierPeriple(tmr) {
+ if (EffetsDraconiques.periple.find(this.casesSpeciales, tmr.coord)) {
+ await this._conquerir(tmr, {
+ difficulte: EffetsDraconiques.periple.getDifficulte(tmr),
+ action: 'Purifier ' + TMRUtility.getTMRDescr(tmr.coord),
+ onConqueteReussie: r => EffetsDraconiques.periple.onVisiteSupprimer(r.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr)),
+ onConqueteEchec: r => {
+ this.souffleSiEchecTotal(rollData);
+ this.close()
+ },
+ canClose: false
+ });
+ }
}
/* -------------------------------------------- */
@@ -576,8 +597,8 @@ export class RdDTMRDialog extends Dialog {
await this._conquerir(tmr, {
difficulte: -7,
action: 'Conquérir',
- onConqueteReussie: r => EffetsDraconiques.conquete.onConquete(r.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr)),
- onConqueteEchec: r => { },
+ onConqueteReussie: r => EffetsDraconiques.conquete.onVisiteSupprimer(r.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr)),
+ onConqueteEchec: r => this.close(),
canClose: false
});
}
@@ -639,8 +660,9 @@ export class RdDTMRDialog extends Dialog {
dialog.render(true);
}
- async validerPelerinage(tmr) {
- await EffetsDraconiques.pelerinage.onFinPelerinage(this.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr));
+ async validerVisite(tmr) {
+ await EffetsDraconiques.pelerinage.onVisiteSupprimer(this.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr));
+ await EffetsDraconiques.urgenceDraconique.onVisiteSupprimer(this.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr));
}
@@ -649,11 +671,12 @@ export class RdDTMRDialog extends Dialog {
let sortReserveList = TMRUtility.getSortReserveList(this.sortsReserves, coord);
if (sortReserveList.length > 0) {
- if (EffetsDraconiques.isSortImpossible(this.actor)) {
+ if (EffetsDraconiques.isSortReserveImpossible(this.actor)) {
ui.notifications.error("Une queue ou un souffle vous empèche de déclencher de sort!");
return;
}
- if (EffetsDraconiques.isReserveEnSecurite(this.actor) || this.isReserveExtensible(coord)) {
+ if (!EffetsDraconiques.isUrgenceDraconique(this.actor) &&
+ (EffetsDraconiques.isReserveEnSecurite(this.actor) || this.isReserveExtensible(coord))) {
let msg = "Vous êtes sur une case avec un Sort en Réserve. Grâce à votre Tête Reserve en Sécurité ou Réserve Exensible, vous pouvez contrôler le déclenchement. Cliquez si vous souhaitez le déclencher : ";
for (let sortReserve of sortReserveList) {
msg += "- " + sortReserve.sort.name + "
";
@@ -663,9 +686,9 @@ export class RdDTMRDialog extends Dialog {
content: msg,
whisper: ChatMessage.getWhisperRecipients(game.user.name)
});
- } else {
- await this.processSortReserve(sortReserveList[0]);
+ return;
}
+ await this.processSortReserve(sortReserveList[0]);
}
}
@@ -835,18 +858,19 @@ export class RdDTMRDialog extends Dialog {
if (!(this.viewOnly || this.currentRencontre)) {
await this.manageCaseHumide(tmr);
await this.conquerirCiteFermee(tmr);
+ await this.purifierPeriple(tmr);
await this.conquerirTMR(tmr);
- await this.validerPelerinage(tmr);
+ await this.validerVisite(tmr);
await this.declencheSortEnReserve(tmr.coord);
await this.actor.checkSoufflePeage(tmr);
}
}
-
+
/* -------------------------------------------- */
async forceDemiRevePositionView() {
this._updateDemiReve();
}
-
+
/* -------------------------------------------- */
async forceDemiRevePosition(coord) {
await this.actor.updateCoordTMR(coord);
diff --git a/module/tmr-utility.js b/module/tmr-utility.js
index aa0358ef..74863674 100644
--- a/module/tmr-utility.js
+++ b/module/tmr-utility.js
@@ -210,8 +210,8 @@ const TMRMapping = {
export const TMRType = {
cite: { name: "cité", genre: "f" },
- sanctuaire: { name: "sanctuaire" },
- plaines: { name: "plaines", genre: "p" },
+ sanctuaire: { name: "sanctuaire", genre: 'm' },
+ plaines: { name: "plaines", genre: "fp" },
pont: { name: "pont", genre: "m" },
collines: { name: "collines", genre: "p" },
foret: { name: "forêt", genre: "f" },
@@ -332,7 +332,12 @@ export class TMRUtility {
}
static getTMRLabel(coord) {
- return TMRMapping[coord]?.label ?? (coord+": case inconnue");
+ return TMRMapping[coord]?.label ?? (coord + ": case inconnue");
+ }
+
+ static getTMRDescr(coord) {
+ const tmr = TMRMapping[coord];
+ return Grammar.articleDetermine(tmr.genre) + ' ' + tmr.label;
}
static isCaseHumide(tmr) {
@@ -384,7 +389,7 @@ export class TMRUtility {
currentPos.x = currentPos.x + direction.x;
currentPos.y = currentPos.y + direction.y;
if (this._checkTMRCoord(currentPos.x, currentPos.y)) { // Sortie de carte ! Ré-insertion aléatoire
- coord = TMRUtility.getTMR(TMRUtility.convertToTMRCoord(currentPos));
+ coord = TMRUtility.getTMR(TMRUtility.convertToTMRCoord(currentPos));
} else {
coord = await actor.reinsertionAleatoire('Sortie de carte');
}
@@ -435,7 +440,7 @@ export class TMRUtility {
return reserveList.filter(it => TMRUtility.getTMR(it.coord).type == 'fleuve');
}
// Reserve sur un case "normale"
- return reserveList.filter(it => it.coord == coord);
+ return reserveList.filter(it => it.coord == coord);
}
/* -------------------------------------------- */
@@ -450,9 +455,8 @@ export class TMRUtility {
for (let dy = -portee; dy <= portee; dy++) { // Loop thru lines
const currentPos = { x: centerPos.x + dx, y: centerPos.y + dy };
if (this._checkTMRCoord(currentPos.x, currentPos.y)) { // Coordinate is valie
- let posPicNow = this.computeRealPictureCoordinates(currentPos, tmrConstants);
- let dist = Math.sqrt(Math.pow(posPicNow.x - posPic.x, 2) + Math.pow(posPicNow.y - posPic.y, 2)) / tmrConstants.cellw;
- if (dist < portee + 0.5) {
+ let dist = this.distancePosTMR(centerPos, currentPos);
+ if (dist <= portee) {
caseList.push(this.convertToTMRCoord(currentPos)); // Inside the area
}
}
@@ -460,5 +464,21 @@ export class TMRUtility {
}
return caseList;
}
+
+ static distanceTMR(coord1, coord2) {
+ let pos1 = this.convertToCellPos(coord1);
+ let pos2 = this.convertToCellPos(coord2);
+ return this.distancePosTMR(pos1, pos2);
+ }
+
+ static distancePosTMR(pos1, pos2) {
+ const dx = pos2.x - pos1.x;
+ const dy = pos2.y - pos1.y;
+ const abs_dx = Math.abs(dx);
+ const abs_dy = Math.abs(dy);
+ const distance = Math.sign(dx) == Math.sign(dy) ? Math.max(abs_dx, abs_dy) : (abs_dx + abs_dy);
+ return distance;
+ }
+
}
diff --git a/module/tmr/conquete.js b/module/tmr/conquete.js
index 92d665c4..ba7dffeb 100644
--- a/module/tmr/conquete.js
+++ b/module/tmr/conquete.js
@@ -35,11 +35,8 @@ export class Conquete extends Draconique {
await this.createCaseTmr(actor, 'Conquête: ' + conquete.label, conquete, queue._id);
}
- async onConquete(actor, tmr, onRemoveToken) {
- let existants = actor.data.items.filter(it => this.isCase(it, tmr.coord));
- for (let casetmr of existants) {
- await actor.deleteOwnedItem(casetmr.data.sourceid);
- onRemoveToken(tmr, casetmr);
- }
+ async onActorDeleteCaseTmr(actor, casetmr) {
+ await actor.deleteOwnedItem(casetmr.data.sourceid);
}
+
}
diff --git a/module/tmr/desorientation.js b/module/tmr/desorientation.js
index f2dad665..1dcec96a 100644
--- a/module/tmr/desorientation.js
+++ b/module/tmr/desorientation.js
@@ -24,10 +24,6 @@ export class Desorientation extends Draconique {
return Object.keys(TMRType).filter(it => !dejaDesorientes.includes(it));
}
- async onActorDeleteOwned(actor, souffle) {
- await this._supprimerCasesTmr(actor, souffle);
- }
-
code() { return 'desorientation' }
tooltip(linkData) { return `Désorientation, cette case n'existe plus !` }
img() { return 'icons/svg/explosion.svg' }
@@ -51,11 +47,5 @@ export class Desorientation extends Draconique {
}
}
- async _supprimerCasesTmr(actor, souffle) {
- let caseTmrs = actor.data.items.filter(it => it.data.sourceId == souffle._id);
- for (let casetmr of caseTmrs) {
- await actor.deleteOwnedItem(casetmr._id);
- }
- }
}
diff --git a/module/tmr/draconique.js b/module/tmr/draconique.js
index 9af391ec..f6b88794 100644
--- a/module/tmr/draconique.js
+++ b/module/tmr/draconique.js
@@ -7,8 +7,7 @@ const registeredEffects = [
/**
* Définition des informations d'une "draconique" (queue, ombre, tête, souffle) qui influence les TMR
*/
-export class Draconique
-{
+export class Draconique {
static isCaseTMR(element) { return element.type == 'casetmr'; }
static isQueueDragon(element) { return element.type == 'queue' || element.type == 'ombre'; }
static isSouffleDragon(element) { return element.type == 'souffle'; }
@@ -28,6 +27,7 @@ export class Draconique
static all() {
return Object.values(registeredEffects);
}
+
static get(code) {
return registeredEffects[code];
}
@@ -56,10 +56,11 @@ export class Draconique
}
async onActorDeleteOwned(actor, item) {
- let caseTmrs = actor.data.items.filter(it => this.isCase(it) && it.data.sourceid == item._id);
- for (let casetmr of caseTmrs) {
- await actor.deleteOwnedItem(casetmr._id);
- }
+ this.deleteCasesTmr(actor, item);
+ return false;
+ }
+
+ async onActorDeleteCaseTmr(actor, casetmr) {
return false;
}
/**
@@ -72,7 +73,7 @@ export class Draconique
* @returns un tooltip à afficher au dessus du token
*/
tooltip(linkData) { return undefined }
-
+
/**
* @param {*} img l'url du fichier image à utiliser pour le token. Si indéfini (et si createSprite n'est pas surchargé),
* un disque est utilisé.
@@ -102,7 +103,7 @@ export class Draconique
if (this.img()) {
return pixiTMR.sprite(this.code());
}
- else{
+ else {
return pixiTMR.circle()
}
}
@@ -120,11 +121,25 @@ export class Draconique
return list.find(c => this.isCase(c, coord));
}
- async createCaseTmr(actor, label, tmr, sourceId=undefined) {
+ async createCaseTmr(actor, label, tmr, sourceId = undefined) {
await actor.createOwnedItem({
name: label, type: 'casetmr', img: this.img(), _id: randomID(16),
- data: { coord: tmr.coord, specific: this.code(), sourceid:sourceId }
+ data: { coord: tmr.coord, specific: this.code(), sourceid: sourceId }
});
}
+ async deleteCasesTmr(actor, draconique) {
+ let caseTmrs = actor.data.items.filter(it => this.isCase(it) && it.data.sourceid == draconique._id);
+ for (let casetmr of caseTmrs) {
+ await actor.deleteOwnedItem(casetmr._id);
+ }
+ }
+
+ async onVisiteSupprimer(actor, tmr, onRemoveToken) {
+ let existants = actor.data.items.filter(it => this.isCase(it, tmr.coord));
+ for (let casetmr of existants) {
+ await actor.deleteOwnedItem(casetmr._id);
+ onRemoveToken(tmr, casetmr);
+ }
+ }
}
\ No newline at end of file
diff --git a/module/tmr/effets-draconiques.js b/module/tmr/effets-draconiques.js
index ab8bdc3d..6eefe7f3 100644
--- a/module/tmr/effets-draconiques.js
+++ b/module/tmr/effets-draconiques.js
@@ -14,6 +14,8 @@ import { PresentCites } from "./present-cites.js";
import { Desorientation } from "./desorientation.js";
import { Conquete } from "./conquete.js";
import { Pelerinage } from "./pelerinage.js";
+import { Periple } from "./periple.js";
+import { UrgenceDraconique } from "./urgence-draconique.js";
export class EffetsDraconiques {
@@ -32,6 +34,8 @@ export class EffetsDraconiques {
static desorientation = new Desorientation();
static conquete = new Conquete();
static pelerinage = new Pelerinage();
+ static periple = new Periple();
+ static urgenceDraconique = new UrgenceDraconique();
static init() {
Draconique.register(EffetsDraconiques.carteTmr);
@@ -49,6 +53,8 @@ export class EffetsDraconiques {
Draconique.register(EffetsDraconiques.desorientation);
Draconique.register(EffetsDraconiques.conquete);
Draconique.register(EffetsDraconiques.pelerinage);
+ Draconique.register(EffetsDraconiques.periple);
+ Draconique.register(EffetsDraconiques.urgenceDraconique);
}
/* -------------------------------------------- */
@@ -112,8 +118,7 @@ export class EffetsDraconiques {
}
static isPeriple(element) {
- // TODO
- return EffetsDraconiques.isMatching(element, it => Draconique.isSouffleDragon(it) && ir.name.toLowerCase() == 'périple');
+ return EffetsDraconiques.isMatching(element, it => EffetsDraconiques.periple.match(it));
}
static isDesorientation(element) {
@@ -122,7 +127,19 @@ export class EffetsDraconiques {
/* -------------------------------------------- */
static isSortImpossible(element) {
- return EffetsDraconiques.isMatching(element, it => EffetsDraconiques.conquete.match(it) || EffetsDraconiques.pelerinage.match(it));
+ return EffetsDraconiques.isMatching(element, it =>
+ EffetsDraconiques.conquete.match(it) ||
+ EffetsDraconiques.periple.match(it) ||
+ EffetsDraconiques.urgenceDraconique.match(it) ||
+ EffetsDraconiques.pelerinage.match(it)
+ );
+ }
+ static isSortReserveImpossible(element) {
+ return EffetsDraconiques.isMatching(element, it =>
+ EffetsDraconiques.conquete.match(it) ||
+ EffetsDraconiques.periple.match(it) ||
+ EffetsDraconiques.pelerinage.match(it)
+ );
}
static isConquete(element) {
@@ -138,7 +155,7 @@ export class EffetsDraconiques {
}
static isUrgenceDraconique(element) {
- return EffetsDraconiques.isMatching(element, it => Draconique.isQueueDragon(it) && it.name.toLowerCase() == 'urgence draconique');
+ return EffetsDraconiques.isMatching(element, it => EffetsDraconiques.urgenceDraconique.match(it));
}
/* -------------------------------------------- */
diff --git a/module/tmr/fermeture-cites.js b/module/tmr/fermeture-cites.js
index 6a8602d3..8d695ae6 100644
--- a/module/tmr/fermeture-cites.js
+++ b/module/tmr/fermeture-cites.js
@@ -35,11 +35,4 @@ export class FermetureCites extends Draconique {
await this.createCaseTmr(actor, 'Fermeture: ' + tmr.label, tmr, souffle._id);
}
}
-
- async onConquete(actor, tmr, onRemoveToken) {
- const citeFermee = actor.data.items.find(it => this.isCase(it, tmr.coord));
- await actor.deleteOwnedItem(citeFermee._id);
- onRemoveToken(tmr, citeFermee);
- }
-
}
diff --git a/module/tmr/pelerinage.js b/module/tmr/pelerinage.js
index 76cc2fe9..ec9e4010 100644
--- a/module/tmr/pelerinage.js
+++ b/module/tmr/pelerinage.js
@@ -31,12 +31,8 @@ export class Pelerinage extends Draconique {
});
}
- async onFinPelerinage(actor, tmr, onRemoveToken) {
- const pelerinages = actor.data.items.filter(it => this.isCase(it, tmr.coord));
- for (let p of pelerinages){
- await actor.deleteOwnedItem(p.data.sourceid);
- onRemoveToken(tmr, p);
- }
+ async onActorDeleteCaseTmr(actor, casetmr) {
+ await actor.deleteOwnedItem(casetmr.data.sourceid);
}
}
diff --git a/module/tmr/periple.js b/module/tmr/periple.js
new file mode 100644
index 00000000..feba1a2b
--- /dev/null
+++ b/module/tmr/periple.js
@@ -0,0 +1,44 @@
+import { Grammar } from "../grammar.js";
+import { tmrColors, tmrConstants, tmrTokenZIndex, TMRUtility } from "../tmr-utility.js";
+import { Draconique } from "./draconique.js";
+
+export class Periple extends Draconique {
+
+ constructor() {
+ super();
+ }
+
+ type() { return 'souffle' }
+ match(item) { return Draconique.isSouffleDragon(item) && Grammar.toLowerCaseNoAccent(item.name).includes('periple'); }
+ manualMessage() { return false }
+
+ async onActorCreateOwned(actor, souffle) {
+ let terrain = new Roll("1d2").evaluate().total == 1 ? 'sanctuaire' : 'necropole';
+ let tmrs = TMRUtility.getListTMR(terrain);
+ for (let tmr of tmrs) {
+ await this.createCaseTmr(actor, 'Périple: ' + tmr.label, tmr, souffle._id);
+ }
+ }
+
+
+ code() { return 'periple' }
+ tooltip(linkData) { return `Votre Périple passe par ${this.tmrDescr(linkData)}` }
+ img() { return 'icons/svg/acid.svg' }
+
+ createSprite(pixiTMR) {
+ return pixiTMR.sprite(this.code(), {
+ zIndex: tmrTokenZIndex.conquete,
+ alpha: 1,
+ color: tmrColors.souffle,
+ taille: tmrConstants.twoThird,
+ decallage: tmrConstants.right
+ });
+ }
+ getDifficulte(tmr) {
+ switch (tmr.type) {
+ case 'sanctuaire': return -3;
+ case 'necropole': return -5;
+ }
+ return 0;
+ }
+}
\ No newline at end of file
diff --git a/module/tmr/rencontre.js b/module/tmr/rencontre.js
index 6bce1a6e..119a6c68 100644
--- a/module/tmr/rencontre.js
+++ b/module/tmr/rencontre.js
@@ -13,7 +13,7 @@ export class Rencontre extends Draconique {
async onActorCreateOwned(actor, item) { }
code() { return 'rencontre' }
- tooltip(linkData) { return `${linkData.name} de force ${linkData.force}` }
+ tooltip(linkData) { return `${linkData.rencontre.name} de force ${linkData.rencontre.force}` }
img() { return 'systems/foundryvtt-reve-de-dragon/icons/heures/hd06.svg' }
createSprite(pixiTMR) {
diff --git a/module/tmr/urgence-draconique.js b/module/tmr/urgence-draconique.js
new file mode 100644
index 00000000..8af5c992
--- /dev/null
+++ b/module/tmr/urgence-draconique.js
@@ -0,0 +1,55 @@
+import { ChatUtility } from "../chat-utility.js";
+import { Grammar } from "../grammar.js";
+import { Misc } from "../misc.js";
+import { RdDRollTables } from "../rdd-rolltables.js";
+import { tmrColors, tmrConstants, tmrTokenZIndex, TMRUtility } from "../tmr-utility.js";
+import { Draconique } from "./draconique.js";
+
+export class UrgenceDraconique extends Draconique {
+
+ constructor() {
+ super();
+ }
+
+ type() { return 'queue' }
+ match(item) { return Draconique.isQueueDragon(item) && Grammar.toLowerCaseNoAccent(item.name).includes('urgence draconique'); }
+ manualMessage() { return false }
+ async onActorCreateOwned(actor, queue) {
+ let coordSortsReserve = (actor.data.data.reve.reserve?.list.map(it => it.coord)) ?? [];
+ if (coordSortsReserve.length == 0) {
+ // La queue se transforme en idée fixe
+ let ideeFixe = await RdDRollTables.getIdeeFixe();
+ ChatMessage.create({
+ whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
+ content: `En l'absence de sorts en réserve, l'urgence draconique de ${actor.name} se transforme en ${queue.name}`
+ });
+ await actor.createOwnedItem(ideeFixe);
+ await actor.deleteOwnedItem(queue._id);
+ return;
+ }
+ else {
+ let demiReve = actor.getDemiReve();
+ coordSortsReserve.sort((a, b) => TMRUtility.distanceTMR(a, demiReve) - TMRUtility.distanceTMR(b, demiReve));
+ let tmr = TMRUtility.getTMR(coordSortsReserve[0]);
+ await this.createCaseTmr(actor, 'Urgence draconique: ' + tmr.label, tmr, queue._id);
+ }
+ }
+
+ async onActorDeleteCaseTmr(actor, casetmr) {
+ await actor.deleteOwnedItem(casetmr.data.sourceid);
+ }
+
+ code() { return 'urgence' }
+ tooltip(linkData) { return `Urgence draconique!` }
+ img() { return 'icons/svg/hazard.svg' }
+
+ createSprite(pixiTMR) {
+ return pixiTMR.sprite(this.code(),
+ {
+ zIndex: tmrTokenZIndex.conquete,
+ color: tmrColors.queues,
+ taille: tmrConstants.full,
+ decallage: { x: 2, y: 0 }
+ });
+ }
+}
diff --git a/templates/actor-sheet.html b/templates/actor-sheet.html
index 84b0b5a8..056359c8 100644
--- a/templates/actor-sheet.html
+++ b/templates/actor-sheet.html
@@ -541,6 +541,7 @@
{{!-- hautreve Tab --}}
+ {{log 'Haut reve' hautreve}}
Haut rêve:
@@ -599,7 +600,7 @@
Sorts en Réserve:
- {{#each data.sortReserve as |reserve key|}}
+ {{#each hautreve.sortsReserve as |reserve key|}}
-
{{reserve.sort.name}} - {{reserve.coord}}
@@ -625,7 +626,7 @@
Cases Spéciales:
- {{#each data.caseSpeciales as |casetmr key|}}
+ {{#each hautreve.casesTmr as |casetmr key|}}
-
{{casetmr.name}}