Compare commits

...

23 Commits

Author SHA1 Message Date
9d51631d5c Merge pull request 'v11.0.27' (#674) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: #674
2023-10-25 00:02:40 +02:00
d1b73e7658 Version 11.0.27 2023-10-24 22:51:45 +02:00
54158ee10d Fix disparition du tooltip dans les TMR
Passage den eventMode static permet de ne pas faire disparaître le
tooltip.
2023-10-24 22:44:51 +02:00
e089bdf9c8 Surencombrement seulement sur actions physiques
CF p70
2023-10-24 22:32:49 +02:00
41ab593059 Fix: fabrication de potion depuis l'herbe
La fabrication ne marchait plus
2023-10-24 22:24:54 +02:00
42ad4c5b26 Fix Restauration TMR si minimisée
Lors d'une action dans les TMRs, si la fenêtre est minimisée,
on la réaffiche
2023-10-24 22:16:49 +02:00
85f8a716d4 Merge pull request '## v11.0.26 - le crépuscule de Khrachtchoum' (#673) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: #673
2023-10-24 07:07:01 +02:00
47f305d865 Les attaques de créatures fonctionnent de nouveau 2023-10-24 00:50:16 +02:00
407b4f82d9 Version 11.0.26 2023-10-24 00:43:16 +02:00
c950f568fd Fix: les TMRs sont en arrière plan 2023-10-24 00:30:00 +02:00
0ed90f6177 Macros pour le corps à corps
Cas particulier car 3 utilisations possibles, et pas d'armes
2023-10-23 23:48:07 +02:00
b74fc27079 Minor cleanup 2023-10-23 23:38:34 +02:00
a65d4511c5 Fix Macros de combat et corps à corps
- gestion des armes à 1/2 mains depuis les armes / le combat
- gestion correcte des compétences d'attaques de créatures
- message pour les macros de compétence d'arme
2023-10-23 23:29:02 +02:00
e61417c44e Merge pull request '## v11.0.25 - la vision du rêve de Khrachtchoum' (#672) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: #672
2023-10-22 21:40:42 +02:00
8ca725bd38 Version 11.0.25 2023-10-22 16:17:53 +02:00
441a5965c7 Fix TMR minimize/maximize
Au lieu de minimiser les TMRs, les actions dans les TMRs sont bloquées
tant qu'une action liée au TMRs est en cours.
2023-10-22 16:17:37 +02:00
f08c8f93da Merge pull request '## v11.0.24 - les couleurs de Khrachtchoum' (#671) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: #671
2023-10-22 09:40:26 +02:00
d28362bf14 Version 11.0.24 2023-10-22 00:36:14 +02:00
e506382d18 typo: Nécropole de Throat 2023-10-22 00:36:10 +02:00
c1cecc76b3 Nouvelles TMRs 2023-10-22 00:19:45 +02:00
f2a3e1db45 Merge pull request 'v11.0.23 - la lumière de Khrachtchoum' (#669) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: #669
2023-10-20 07:12:09 +02:00
b69359a47d Version 11.0.23 2023-10-20 02:36:49 +02:00
fe6c2e2ff2 Ajustement de luminosité automatique
Activable par le MJ avec le bouton lumière du calendrier
2023-10-20 02:36:00 +02:00
31 changed files with 562 additions and 283 deletions

View File

@@ -1,5 +1,41 @@
# v11.0 # v11.0
## v11.0.21 ## v11.0.27 - Khrachtchoum le méticuleux
- le tooltip dans les TMR reste visible si on ne bouge pas la souris
- le surencombrement n'affecte QUE les actions physiques
- on peut de nouveau fabriquer une potion depuis la fenêtre d'édition de l'herbe
- si les TMR sont minimisées alors qu'une action est requise, elles sont bien réaffichées lorsque l'action est faite
## v11.0.26 - le crépuscule de Khrachtchoum
- gestion correcte des TMRs
- les TMRs ne sont jamais minimisées (par le système) quand le haut-rêvant est en demi-rêve
- lorsqu'une fenêtre liée aux demi-rêve est affichée, cliquer sur les TMRs n'a pas d'effet
- les lancers de sorts et lectures de signes sont affichées en premier plan
- Les effets qui ouvrent une fenêtre sont bien affichés en premier plan
- en cas de rencontre suivie de maîtrises/conquêtes, les fenêtres s'enchaînent
- Le drag&drop vers la barre de macro est corrigé
- pour les créatures, possibilités d'avoir les attaques ou autres compétences
- pour les personnages, les macros sont créées:
- pour les compétences
- pour le corps à corps, trois macros sont créées: compétence, pugilat, empoignade
- pour les armes
- deux macros sont créées pour les armes à 1/2 mains
- deux macros sont créées pour les armes de mélée et lancer
- 4 macros si votre arbalête se lance, tire, et se manie à 1 ou 2 mains...
- les jets de compétences d'attaque des créatures fonctionnent de nouveau
## v11.0.25 - la vision du rêve de Khrachtchoum
- Les TMRs restent affichées tant que le Haut-rêvant est en demi-rêve
## v11.0.24 - les couleurs de Khrachtchoum
- nouvelle carte des TMRs
## v11.0.23 - la lumière de Khrachtchoum
- ajustement automatique de la luminosité selon l'heure pour les scènes:
- avec une vision des tokens (sinon: ce n'est pas une scène de carte pour tokens)
- avec illumination globale (correspondant à une illumination extérieure)
- quand lampe "allumée" dans la fenêtre du calendrier
## v11.0.22 - les automatismes de Khrachtchoum le Problémeux
- Macro pour attaquer avec les compétences de créatures - Macro pour attaquer avec les compétences de créatures
## v11.0.20 ## v11.0.20

View File

@@ -81,9 +81,12 @@ export class RdDActorSheet extends RdDBaseActorSheet {
}); });
// toujours avoir une liste d'armes (pour mettre esquive et corps à corps) // toujours avoir une liste d'armes (pour mettre esquive et corps à corps)
formData.combat = duplicate(formData.armes ?? []); const actor = this.actor;
formData.combat = duplicate(formData.armes);
RdDItemArme.computeNiveauArmes(formData.combat, formData.competences); RdDItemArme.computeNiveauArmes(formData.combat, formData.competences);
RdDItemArme.ajoutCorpsACorps(formData.combat, formData.competences, formData.system.carac); formData.combat.push(RdDItemArme.mainsNues(actor));
formData.combat.push(RdDItemArme.empoignade(actor));
formData.esquives = this.actor.getCompetences("Esquive"); formData.esquives = this.actor.getCompetences("Esquive");
formData.combat = RdDCombatManager.listActionsArmes(formData.combat, formData.competences, formData.system.carac); formData.combat = RdDCombatManager.listActionsArmes(formData.combat, formData.competences, formData.system.carac);
formData.empoignades = this.actor.getEmpoignades(); formData.empoignades = this.actor.getEmpoignades();

View File

@@ -232,12 +232,21 @@ export class RdDActor extends RdDBaseActor {
/* -------------------------------------------- */ /* -------------------------------------------- */
getCompetence(idOrName, options = {}) { getCompetence(idOrName, options = {}) {
if (idOrName instanceof Item) {
return idOrName.isCompetence() ? idOrName : undefined
}
return RdDItemCompetence.findCompetence(this.items, idOrName, options) return RdDItemCompetence.findCompetence(this.items, idOrName, options)
} }
getCompetences(name) { getCompetences(name) {
return RdDItemCompetence.findCompetences(this.items, name) return RdDItemCompetence.findCompetences(this.items, name)
} }
getCompetenceCorpsACorps(options = {}) {
return this.getCompetence("Corps à corps", options)
}
getCompetencesEsquive() {
return this.getCompetences("esquive")
}
/* -------------------------------------------- */ /* -------------------------------------------- */
getTache(id) { getTache(id) {
return this.findItemLike(id, 'tache'); return this.findItemLike(id, 'tache');
@@ -288,13 +297,13 @@ export class RdDActor extends RdDBaseActor {
} }
getPossession(possessionId) { getPossession(possessionId) {
return this.items.find(it => it.type == TYPES.possession && it.system.possessionid == possessionId); return this.itemTypes[TYPES.possession].find(it => it.system.possessionid == possessionId);
} }
getPossessions() { getPossessions() {
return this.items.filter(it => it.type == TYPES.possession); return this.itemTypes[TYPES.possession];
} }
getEmpoignades() { getEmpoignades() {
return this.items.filter(it => it.type == TYPES.empoignade); return this.itemTypes[TYPES.empoignade];
} }
getDemiReve() { getDemiReve() {
return this.system.reve.tmrpos.coord; return this.system.reve.tmrpos.coord;
@@ -369,7 +378,7 @@ export class RdDActor extends RdDBaseActor {
async _openRollDialog({ name, label, template, rollData, callbackAction }) { async _openRollDialog({ name, label, template, rollData, callbackAction }) {
const dialog = await RdDRoll.create(this, rollData, const dialog = await RdDRoll.create(this, rollData,
{ html: template }, { html: template, close: html => { this.tmrApp?.restoreTMRAfterAction() } },
{ {
name: name, name: name,
label: label, label: label,
@@ -380,6 +389,7 @@ export class RdDActor extends RdDBaseActor {
] ]
}); });
dialog.render(true); dialog.render(true);
return dialog
} }
@@ -545,7 +555,7 @@ export class RdDActor extends RdDBaseActor {
/* -------------------------------------------- */ /* -------------------------------------------- */
async _recuperationBlessures(message, isMaladeEmpoisonne) { async _recuperationBlessures(message, isMaladeEmpoisonne) {
const timestamp = game.system.rdd.calendrier.getTimestamp() const timestamp = game.system.rdd.calendrier.getTimestamp()
const blessures = this.filterItems(it => it.system.gravite > 0, 'blessure').sort(Misc.ascending(it => it.system.gravite)) const blessures = this.filterItems(it => it.system.gravite > 0, TYPES.blessure).sort(Misc.ascending(it => it.system.gravite))
await Promise.all(blessures.map(b => b.recuperationBlessure({ await Promise.all(blessures.map(b => b.recuperationBlessure({
actor: this, actor: this,
@@ -559,7 +569,7 @@ export class RdDActor extends RdDBaseActor {
} }
async supprimerBlessures(filterToDelete) { async supprimerBlessures(filterToDelete) {
const toDelete = this.filterItems(filterToDelete, 'blessure') const toDelete = this.filterItems(filterToDelete, TYPES.blessure)
.map(it => it.id); .map(it => it.id);
await this.deleteEmbeddedDocuments('Item', toDelete); await this.deleteEmbeddedDocuments('Item', toDelete);
} }
@@ -567,7 +577,7 @@ export class RdDActor extends RdDBaseActor {
/* -------------------------------------------- */ /* -------------------------------------------- */
async _recupererVie(message, isMaladeEmpoisonne) { async _recupererVie(message, isMaladeEmpoisonne) {
const tData = this.system const tData = this.system
let blessures = this.filterItems(it => it.system.gravite > 0, 'blessure'); let blessures = this.filterItems(it => it.system.gravite > 0, TYPES.blessure);
if (blessures.length > 0) { if (blessures.length > 0) {
return return
} }
@@ -846,7 +856,7 @@ export class RdDActor extends RdDBaseActor {
system: { sortid: sort._id, draconic: (draconic?.name ?? sort.system.draconic), ptreve: ptreve, coord: coord, heurecible: 'Vaisseau' } system: { sortid: sort._id, draconic: (draconic?.name ?? sort.system.draconic), ptreve: ptreve, coord: coord, heurecible: 'Vaisseau' }
}], }],
{ renderSheet: false }); { renderSheet: false });
this.currentTMR.updateTokens(); this.tmrApp.updateTokens();
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -2138,12 +2148,11 @@ export class RdDActor extends RdDBaseActor {
ui.notifications.info(`Aucun sort disponible en ${TMRUtility.getTMR(coord).label} !`); ui.notifications.info(`Aucun sort disponible en ${TMRUtility.getTMR(coord).label} !`);
return; return;
} }
if (this.currentTMR) this.currentTMR.minimize(); // Hide
const draconicList = this.computeDraconicAndSortIndex(sorts); const draconicList = this.computeDraconicAndSortIndex(sorts);
const reve = duplicate(this.system.carac.reve); const reve = duplicate(this.system.carac.reve);
await this._openRollDialog({ const dialog = await this._openRollDialog({
name: 'lancer-un-sort', name: 'lancer-un-sort',
label: 'Lancer un sort', label: 'Lancer un sort',
template: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-sort.html', template: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-sort.html',
@@ -2159,8 +2168,12 @@ export class RdDActor extends RdDBaseActor {
diffLibre: RdDItemSort.getDifficulte(sorts[0], -7), // Per default at startup diffLibre: RdDItemSort.getDifficulte(sorts[0], -7), // Per default at startup
coutreve: Array(30).fill().map((item, index) => 1 + index), coutreve: Array(30).fill().map((item, index) => 1 + index),
}, },
callbackAction: r => this._rollUnSortResult(r) callbackAction: async r => {
await this._rollUnSortResult(r);
if (!r.isSortReserve) this.tmrApp?.close();
}
}); });
this.tmrApp?.setTMRPendingAction(dialog);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -2251,17 +2264,11 @@ export class RdDActor extends RdDBaseActor {
reveActuel = Math.max(reveActuel - rollData.depenseReve, 0); reveActuel = Math.max(reveActuel - rollData.depenseReve, 0);
await this.update({ "system.reve.reve.value": reveActuel }); await this.update({ "system.reve.reve.value": reveActuel });
if (rollData.isSortReserve) {
this.currentTMR.maximize(); // Re-display TMR
} else {
this.currentTMR.close(); // Close TMR !
}
// Final chat message // Final chat message
await RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-sort.html'); await RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-sort.html');
if (reveActuel == 0) { // 0 points de reve if (reveActuel == 0) { // 0 points de reve
ChatMessage.create({ content: this.name + " est réduit à 0 Points de Rêve, et tombe endormi !" }); ChatMessage.create({ content: this.name + " est réduit à 0 Points de Rêve, et tombe endormi !" });
closeTMR = true;
} }
} }
@@ -2336,16 +2343,14 @@ export class RdDActor extends RdDBaseActor {
/* -------------------------------------------- */ /* -------------------------------------------- */
async rollCompetence(idOrName, options = { tryTarget: true }) { async rollCompetence(idOrName, options = { tryTarget: true }) {
RdDEmpoignade.checkEmpoignadeEnCours(this) RdDEmpoignade.checkEmpoignadeEnCours(this)
let rollData = { const competence = this.getCompetence(idOrName);
carac: this.system.carac, let rollData = { carac: this.system.carac, competence: competence }
competence: this.getCompetence(idOrName) if (competence.type == TYPES.competencecreature) {
} const arme = RdDItemCompetenceCreature.armeCreature(competence)
if (rollData.competence.type == TYPES.competencecreature) {
const arme = RdDItemCompetenceCreature.armeCreature(rollData.competence)
if (arme && options.tryTarget && Targets.hasTargets()) { if (arme && options.tryTarget && Targets.hasTargets()) {
Targets.selectOneToken(target => { Targets.selectOneToken(target => {
if (arme.action == "possession") { if (arme.action == "possession") {
RdDPossession.onAttaquePossession(target, this, rollData.competence) RdDPossession.onAttaquePossession(target, this, competence)
} }
else { else {
RdDCombat.rddCombatTarget(target, this).attaque(competence, arme) RdDCombat.rddCombatTarget(target, this).attaque(competence, arme)
@@ -2359,7 +2364,7 @@ export class RdDActor extends RdDBaseActor {
await this._openRollDialog({ await this._openRollDialog({
name: 'jet-competence', name: 'jet-competence',
label: 'Jet ' + Grammar.apostrophe('de', rollData.competence.name), label: 'Jet ' + Grammar.apostrophe('de', competence.name),
template: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html', template: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html',
rollData: rollData, rollData: rollData,
callbackAction: r => this.$onRollCompetence(r, options) callbackAction: r => this.$onRollCompetence(r, options)
@@ -2723,8 +2728,6 @@ export class RdDActor extends RdDBaseActor {
ui.notifications.info(`Aucun signe draconiques en ${coord} !`); ui.notifications.info(`Aucun signe draconiques en ${coord} !`);
return; return;
} }
if (this.currentTMR) this.currentTMR.minimize(); // Hide
let draconicList = this.getDraconicList() let draconicList = this.getDraconicList()
.map(draconic => { .map(draconic => {
let draconicLecture = duplicate(draconic); let draconicLecture = duplicate(draconic);
@@ -2747,7 +2750,7 @@ export class RdDActor extends RdDBaseActor {
const dialog = await RdDRoll.create(this, rollData, const dialog = await RdDRoll.create(this, rollData,
{ {
html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-signedraconique.html', html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-signedraconique.html',
close: html => { this.currentTMR.maximize() } // Re-display TMR close: html => { this.tmrApp?.restoreTMRAfterAction() }
}, },
{ {
name: 'lire-signe-draconique', name: 'lire-signe-draconique',
@@ -2759,6 +2762,7 @@ export class RdDActor extends RdDBaseActor {
} }
); );
dialog.render(true); dialog.render(true);
this.tmrApp?.setTMRPendingAction(dialog);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -2777,7 +2781,7 @@ export class RdDActor extends RdDBaseActor {
} }
await this.deleteEmbeddedDocuments("Item", [rollData.signe._id]); await this.deleteEmbeddedDocuments("Item", [rollData.signe._id]);
await RdDResolutionTable.displayRollData(rollData, this.name, 'chat-resultat-lecture-signedraconique.html'); await RdDResolutionTable.displayRollData(rollData, this.name, 'chat-resultat-lecture-signedraconique.html');
this.currentTMR.close(); this.tmrApp.close();
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -3012,8 +3016,8 @@ export class RdDActor extends RdDBaseActor {
/* -------------------------------------------- */ /* -------------------------------------------- */
refreshTMRView() { refreshTMRView() {
if (this.currentTMR) { if (this.tmrApp) {
this.currentTMR.externalRefresh(); this.tmrApp.externalRefresh();
} }
} }
@@ -3021,6 +3025,7 @@ export class RdDActor extends RdDBaseActor {
async displayTMR(mode = "normal") { async displayTMR(mode = "normal") {
if (this.tmrApp) { if (this.tmrApp) {
ui.notifications.warn("Vous êtes déja dans les TMR...."); ui.notifications.warn("Vous êtes déja dans les TMR....");
this.tmrApp.forceTMRDisplay();
return return
} }
if (mode != 'visu' && this.getEffect(STATUSES.StatusDemiReve)) { if (mode != 'visu' && this.getEffect(STATUSES.StatusDemiReve)) {
@@ -3066,29 +3071,40 @@ export class RdDActor extends RdDBaseActor {
hasPlayerOwner: this.hasPlayerOwner hasPlayerOwner: this.hasPlayerOwner
} }
this.currentTMR = await RdDTMRDialog.create(this, tmrFormData); this.tmrApp = await RdDTMRDialog.create(this, tmrFormData);
this.currentTMR.render(true); this.tmrApp.render(true);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
getArmeCompetence(arme, competenceName) { getCompetenceArme(arme, competenceName) {
let comp = arme.system[competenceName] switch (arme.type) {
if (!comp || comp.name == "") { case TYPES.competencecreature:
comp = arme.system[competenceName] return arme.name
case TYPES.arme:
switch (competenceName) {
case 'competence': return arme.system.competence;
case 'unemain': return RdDItemArme.competence1Mains(arme);
case 'deuxmains': return RdDItemArme.competence2Mains(arme);
case 'tir': return arme.system.tir;
case 'lancer': return arme.system.lancer;
} }
if ( !comp || comp.name == "") {
comp = arme.system[competenceName]
} }
return comp return undefined
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
rollArme(arme, competenceName = "competence") { /**
let compToUse = this.getArmeCompetence(arme, competenceName) *
* @param {*} arme item d'arme/compétence de créature
* @param {*} categorieArme catégorie d'attaque à utiliser: competence (== melee), lancer, tir; naturelle, possession
* @returns
*/
rollArme(arme, categorieArme = "competence") {
let compToUse = this.getCompetenceArme(arme, categorieArme)
if (!Targets.hasTargets()) { if (!Targets.hasTargets()) {
RdDConfirm.confirmer({ RdDConfirm.confirmer({
settingConfirmer: "confirmer-combat-sans-cible", settingConfirmer: "confirmer-combat-sans-cible",
content: `<p>Voulez vous faire un jet de compétence ${competenceName} sans choisir de cible valide? content: `<p>Voulez vous faire un jet de ${compToUse} sans choisir de cible valide?
<br>Tous les jets de combats devront être gérés à la main <br>Tous les jets de combats devront être gérés à la main
</p>`, </p>`,
title: 'Ne pas utiliser les automatisation de combat', title: 'Ne pas utiliser les automatisation de combat',

View File

@@ -20,14 +20,14 @@ const nomCategorieParade = {
export class RdDItemArme extends Item { export class RdDItemArme extends Item {
static isArme(item) { static isArme(item) {
return RdDItemCompetenceCreature.getCategorieAttaque(item) || item.type == 'arme'; return RdDItemCompetenceCreature.getCategorieAttaque(item) || item.type == TYPES.arme;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static getArme(arme) { static getArme(arme) {
switch (arme ? arme.type : '') { switch (arme ? arme.type : '') {
case 'arme': return arme; case TYPES.arme: return arme;
case 'competencecreature': case TYPES.competencecreature:
return RdDItemCompetenceCreature.armeCreature(arme); return RdDItemCompetenceCreature.armeCreature(arme);
} }
return RdDItemArme.mainsNues(); return RdDItemArme.mainsNues();
@@ -68,14 +68,14 @@ export class RdDItemArme extends Item {
return armeData.system.categorie_parade; return armeData.system.categorie_parade;
} }
// pour compatibilité avec des personnages existants // pour compatibilité avec des personnages existants
if (armeData.type == 'competencecreature' || armeData.system.categorie == 'creature') { if (armeData.type == TYPES.competencecreature || armeData.system.categorie == 'creature') {
return armeData.system.categorie_parade || (armeData.system.isparade ? 'armes-naturelles' : ''); return armeData.system.categorie_parade || (armeData.system.isparade ? 'armes-naturelles' : '');
} }
if (!armeData.type.match(/arme|competencecreature/)) { if (!armeData.type.match(/arme|competencecreature/)) {
return ''; return '';
} }
if (armeData.system.competence == undefined) { if (armeData.system.competence == undefined) {
return 'competencecreature'; return TYPES.competencecreature;
} }
let compname = armeData.system.competence.toLowerCase(); let compname = armeData.system.competence.toLowerCase();
if (compname.match(/^(dague de jet|javelot|fouet|arc|arbalête|fronde|hache de jet|fléau)$/)) return ''; if (compname.match(/^(dague de jet|javelot|fouet|arc|arbalête|fronde|hache de jet|fléau)$/)) return '';
@@ -157,23 +157,33 @@ export class RdDItemArme extends Item {
} }
return armeData; return armeData;
} }
static competence2Mains(arme) {
return arme.system.competence.replace(" 1 main", " 2 mains");
}
static competence1Mains(arme) {
return arme.system.competence.replace(" 2 mains", " 1 main");
}
static isArmeUtilisable(arme) { static isArmeUtilisable(arme) {
return arme.type == 'arme' && arme.system.equipe && (arme.system.resistance > 0 || arme.system.portee_courte > 0); return arme.type == 'arme' && arme.system.equipe && (arme.system.resistance > 0 || arme.system.portee_courte > 0);
} }
static ajoutCorpsACorps(armes, competences, carac) { static ajoutCorpsACorps(armes, actor) {
let corpsACorps = competences.find(it => it.name == 'Corps à corps') ?? { system: { niveau: -6 } }; armes.push(RdDItemArme.mainsNues(actor));
let init = RdDCombatManager.calculInitiative(corpsACorps.system.niveau, carac['melee'].value); armes.push(RdDItemArme.empoignade(actor));
armes.push(RdDItemArme.mainsNues({ niveau: corpsACorps.system.niveau, initiative: init }));
armes.push(RdDItemArme.empoignade({ niveau: corpsACorps.system.niveau, initiative: init }));
} }
static corpsACorps(mainsNuesActor) { static corpsACorps(actor) {
const corpsACorps = { let competence = actor?.getCompetenceCorpsACorps() ?? { system: { niveau: -6 } };
let melee = actor? actor.system.carac['melee'].value : 0
return {
_id: competence?.id,
name: 'Corps à corps', name: 'Corps à corps',
type: TYPES.arme,
img: 'systems/foundryvtt-reve-de-dragon/icons/competence_corps_a_corps.webp', img: 'systems/foundryvtt-reve-de-dragon/icons/competence_corps_a_corps.webp',
system: { system: {
initiative: RdDCombatManager.calculInitiative(competence.system.niveau, melee),
equipe: true, equipe: true,
rapide: true, rapide: true,
force: 0, force: 0,
@@ -181,23 +191,22 @@ export class RdDItemArme extends Item {
dommagesReels: 0, dommagesReels: 0,
mortalite: 'non-mortel', mortalite: 'non-mortel',
competence: 'Corps à corps', competence: 'Corps à corps',
deuxmains: true,
categorie_parade: 'sans-armes' categorie_parade: 'sans-armes'
} }
}; }
mergeObject(corpsACorps.system, mainsNuesActor ?? {}, { overwrite: false });
return corpsACorps;
} }
static mainsNues(mainsNuesActor) { static mainsNues(actor) {
const mainsNues = RdDItemArme.corpsACorps(mainsNuesActor) const mainsNues = RdDItemArme.corpsACorps(actor)
mainsNues.name = 'Mains nues' mainsNues.name = 'Mains nues'
mainsNues.system.cac = 'pugilat' mainsNues.system.cac = 'pugilat'
mainsNues.system.baseInit = 4 mainsNues.system.baseInit = 4
return mainsNues; return mainsNues;
} }
static empoignade(mainsNuesActor) { static empoignade(actor) {
const empoignade = RdDItemArme.corpsACorps(mainsNuesActor) const empoignade = RdDItemArme.corpsACorps(actor)
empoignade.name = 'Empoignade' empoignade.name = 'Empoignade'
empoignade.system.cac = 'empoignade' empoignade.system.cac = 'empoignade'
empoignade.system.baseInit = 3 empoignade.system.baseInit = 3

View File

@@ -79,10 +79,9 @@ export class RdDItemCompetence extends Item {
/* -------------------------------------------- */ /* -------------------------------------------- */
static isCompetenceArme(competence) { static isCompetenceArme(competence) {
if (competence.isCompetence()) { if (competence.isCompetence() && !competence.isCorpsACorps() && !competence.isEsquive()) {
switch (competence.system.categorie) { switch (competence.system.categorie) {
case 'melee': case 'melee':
return !Grammar.toLowerCaseNoAccent(competence.name).includes('esquive');
case 'tir': case 'tir':
case 'lancer': case 'lancer':
return true; return true;
@@ -93,10 +92,10 @@ export class RdDItemCompetence extends Item {
/* -------------------------------------------- */ /* -------------------------------------------- */
static isArmeUneMain(competence) { static isArmeUneMain(competence) {
return RdDItemCompetence.isCompetenceArme(competence) && competence.name.toLowerCase().includes("1 main"); return competence.isCompetenceArme() && competence.name.toLowerCase().includes("1 main");
} }
static isArme2Main(competence) { static isArme2Main(competence) {
return RdDItemCompetence.isCompetenceArme(competence) && competence.name.toLowerCase().includes("2 main"); return competence.isCompetenceArme() && competence.name.toLowerCase().includes("2 main");
} }
static isThanatos(competence) { static isThanatos(competence) {

View File

@@ -1,5 +1,5 @@
import { RdDItem, TYPES } from "./item.js"; import { TYPES } from "./item.js";
import { RdDCombatManager } from "./rdd-combat.js"; import { RdDCombatManager } from "./rdd-combat.js";
const categories = { const categories = {

View File

@@ -113,7 +113,7 @@ export class RdDItemSheet extends ItemSheet {
formData.competences = competences; formData.competences = competences;
} }
if (this.item.type == 'arme') { if (this.item.type == 'arme') {
formData.competences = competences.filter(it => RdDItemCompetence.isCompetenceArme(it)) formData.competences = competences.filter(it => it.isCompetenceArme())
} }
if (['sort', 'sortreserve'].includes(this.item.type)) { if (['sort', 'sortreserve'].includes(this.item.type)) {
formData.competences = competences.filter(it => RdDItemCompetence.isDraconic(it)); formData.competences = competences.filter(it => RdDItemCompetence.isDraconic(it));
@@ -195,7 +195,7 @@ export class RdDItemSheet extends ItemSheet {
this.html.find('.creer-tache-livre').click((event) => this._getEventActor(event).creerTacheDepuisLivre(this.item)); this.html.find('.creer-tache-livre').click((event) => this._getEventActor(event).creerTacheDepuisLivre(this.item));
this.html.find('.consommer-potion').click((event) => this._getEventActor(event).consommerPotion(this.item, this.getActionRenderItem())); this.html.find('.consommer-potion').click((event) => this._getEventActor(event).consommerPotion(this.item, this.getActionRenderItem()));
this.html.find('.creer-potion-base').click((event) => this._getEventActor(event).dialogFabriquerPotion(this.item)); this.html.find('.creer-potion-base').click((event) => this._getEventActor(event).actionHerbe(this.item));
this.html.find('.alchimie-tache a').click((event) => { this.html.find('.alchimie-tache a').click((event) => {
let actor = this._getEventActor(event); let actor = this._getEventActor(event);

View File

@@ -220,6 +220,32 @@ export class RdDItem extends Item {
isService() { return this.type == TYPES.service; } isService() { return this.type == TYPES.service; }
isCompetence() { return typesObjetsCompetence.includes(this.type) } isCompetence() { return typesObjetsCompetence.includes(this.type) }
isEsquive() {
return (this.isCompetence()
&& this.system.categorie == 'melee'
&& Grammar.includesLowerCaseNoAccent(this.name, 'Esquive'));
}
isCorpsACorps() {
return (this.isCompetence()
&& this.system.categorie == 'melee'
&& Grammar.includesLowerCaseNoAccent(this.name, 'Corps à Corps'));
}
isCompetenceArme() {
if (this.isCompetence()) {
switch (this.system.categorie) {
case 'melee':
return !this.isCorpsACorps() && !this.isEsquive()
case 'tir':
case 'lancer':
return true;
}
}
return false;
}
isCompetencePossession() { return TYPES.competencecreature == this.type && this.system.categorie == "possession" } isCompetencePossession() { return TYPES.competencecreature == this.type && this.system.categorie == "possession" }
isTemporel() { return typesObjetsTemporels.includes(this.type) } isTemporel() { return typesObjetsTemporels.includes(this.type) }
isOeuvre() { return typesObjetsOeuvres.includes(this.type) } isOeuvre() { return typesObjetsOeuvres.includes(this.type) }

View File

@@ -171,8 +171,7 @@ export class RdDCombatManager extends Combat {
if (arme.system.unemain && arme.system.deuxmains && !dommages.includes("/")) { if (arme.system.unemain && arme.system.deuxmains && !dommages.includes("/")) {
ui.notifications.info("Les dommages de l'arme à 1/2 mains " + arme.name + " ne sont pas corrects (ie sous la forme X/Y)"); ui.notifications.info("Les dommages de l'arme à 1/2 mains " + arme.name + " ne sont pas corrects (ie sous la forme X/Y)");
} }
if ((arme.system.unemain && arme.system.competence) || if (arme.system.unemain && arme.system.competence) {
(arme.system.competence.toLowerCase().includes("corps à corps"))) {
actions.push(RdDCombatManager.$prepareAttaqueArme({ actions.push(RdDCombatManager.$prepareAttaqueArme({
arme: arme, arme: arme,
infoMain: "(1 main)", infoMain: "(1 main)",
@@ -187,7 +186,7 @@ export class RdDCombatManager extends Combat {
arme: arme, arme: arme,
infoMain: "(2 mains)", infoMain: "(2 mains)",
dommagesReel: Number(tableauDommages[1]), dommagesReel: Number(tableauDommages[1]),
competence: arme.system.competence.replace(" 1 main", " 2 mains"), competence: RdDItemArme.competence2Mains(arme),
carac: carac, carac: carac,
competences: competences competences: competences
})); }));
@@ -258,11 +257,10 @@ export class RdDCombatManager extends Combat {
actions = RdDCombatManager.listActionsCreature(actor.itemTypes['competencecreature']); actions = RdDCombatManager.listActionsCreature(actor.itemTypes['competencecreature']);
} else if (actor.isPersonnage()) { } else if (actor.isPersonnage()) {
// Recupération des items 'arme' // Recupération des items 'arme'
const armes = actor.itemTypes['arme'].filter(it => RdDItemArme.isArmeUtilisable(it))
.concat(RdDItemArme.empoignade())
.concat(RdDItemArme.mainsNues());
const competences = actor.itemTypes['competence']; const competences = actor.itemTypes['competence'];
const armes = actor.itemTypes['arme'].filter(it => RdDItemArme.isArmeUtilisable(it))
.concat(RdDItemArme.empoignade(actor))
.concat(RdDItemArme.mainsNues(actor));
actions = RdDCombatManager.listActionsArmes(armes, competences, actor.system.carac); actions = RdDCombatManager.listActionsArmes(armes, competences, actor.system.carac);
if (actor.system.attributs.hautrevant.value) { if (actor.system.attributs.hautrevant.value) {
@@ -885,8 +883,8 @@ export class RdDCombat {
} }
// # utilisation esquive // # utilisation esquive
const corpsACorps = this.defender.getCompetence("Corps à corps", { onMessage: it => console.info(it, this.defender) }); const corpsACorps = this.defender.getCompetenceCorpsACorps({ onMessage: it => console.info(it, this.defender) });
const esquives = duplicate(this.defender.getCompetences("esquive", { onMessage: it => console.info(it, this.defender) })) const esquives = duplicate(this.defender.getCompetencesEsquive())
esquives.forEach(e => e.system.nbUsage = e?._id ? this.defender.getItemUse(e._id) : 0); esquives.forEach(e => e.system.nbUsage = e?._id ? this.defender.getItemUse(e._id) : 0);
const paramChatDefense = { const paramChatDefense = {

View File

@@ -181,7 +181,7 @@ export class RdDEmpoignade {
let rollData = { let rollData = {
mode, empoignade, attacker, defender, mode, empoignade, attacker, defender,
isEmpoignade: true, isEmpoignade: true,
competence: attacker.getCompetence("Corps à corps"), competence: attacker.getCompetenceCorpsACorps(),
selectedCarac: attacker.system.carac.melee, selectedCarac: attacker.system.carac.melee,
malusTaille: RdDEmpoignade.getMalusTaille(empoignade, attacker, defender) malusTaille: RdDEmpoignade.getMalusTaille(empoignade, attacker, defender)
} }
@@ -210,7 +210,7 @@ export class RdDEmpoignade {
mode: "immobilise", mode: "immobilise",
empoignade, attacker, defender, empoignade, attacker, defender,
isEmpoignade: true, isEmpoignade: true,
competence: attacker.getCompetence("Corps à corps") competence: attacker.getCompetenceCorpsACorps()
} }
const msg = await ChatMessage.create({ const msg = await ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(attacker.name), whisper: ChatUtility.getWhisperRecipientsAndGMs(attacker.name),

View File

@@ -1,13 +1,17 @@
import { RdDItemArme } from "./item-arme.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { TYPES } from "./item.js"; import { TYPES } from "./item.js";
export class RdDHotbar { export class RdDHotbar {
static async createItemMacro(item, slot, armeCompetence = undefined) { static async createItemMacro(item, slot, armeCompetence = undefined) {
let command = `game.system.rdd.RdDHotbar.rollMacro("${item.name}", "${item.type}"` + ((armeCompetence) ? `, "${armeCompetence}");` : `);`); const itemName = item.name;
let macro = game.macros.contents.find(m => (m.name === item.name) && (m.command === command)); let macroName = itemName + RdDHotbar.$macroNameSuffix(armeCompetence);
let command = `game.system.rdd.RdDHotbar.rollMacro("${itemName}", "${item.type}", "${armeCompetence}");`
let macro = game.macros.contents.find(m => (m.name === itemName) && (m.command === command));
if (!macro) { if (!macro) {
macro = await Macro.create({ macro = await Macro.create({
name: item.name, name: macroName,
type: "script", type: "script",
img: item.img, img: item.img,
command: command command: command
@@ -16,29 +20,55 @@ export class RdDHotbar {
await game.user.assignHotbarMacro(macro, slot); await game.user.assignHotbarMacro(macro, slot);
} }
static $macroNameSuffix(armeCompetence) {
switch (armeCompetence) {
case 'unemain': return ' (1 main)';
case 'deuxmains': return ' (2 main)';
case 'tir': return ' (tir)';
case 'lancer': return ' (lancer)';
case 'pugilat': return ' (pugilat)';
case 'empoignade': return ' (empoignade)';
}
return ''
}
static async addToHotbar(item, slot) { static async addToHotbar(item, slot) {
switch (item?.type ?? "") { switch (item?.type ?? '') {
case TYPES.arme: case TYPES.arme:
{ {
// Les armes peuvent avoir plusieurs usages // Les armes peuvent avoir plusieurs usages
if (item.system.competence != "") { if (item.system.competence != '') {
await this.createItemMacro(item, slot, "competence") if (item.system.unemain) {
slot++ await this.createItemMacro(item, slot++, 'unemain')
} }
if (item.system.lancer != "") { if (item.system.deuxmains) {
await this.createItemMacro(item, slot, "lancer") await this.createItemMacro(item, slot++, 'deuxmains')
slot++
} }
if (item.system.tir != "") { }
await this.createItemMacro(item, slot, "lancer") if (item.system.lancer != '') {
slot++ await this.createItemMacro(item, slot++, 'lancer')
}
if (item.system.tir != '') {
await this.createItemMacro(item, slot++, 'lancer')
} }
} }
return return
case TYPES.competence:
case TYPES.competencecreature: case TYPES.competencecreature:
const categorie = RdDItemCompetenceCreature.getCategorieAttaque(item) ?? 'competence';
await this.createItemMacro(item, slot, categorie)
return
default: default:
await this.createItemMacro(item, slot) case TYPES.competence:
await this.createItemMacro(item, slot++, 'competence')
if (item.isCorpsACorps()) {
await this.createItemMacro(item, slot++, 'pugilat')
await this.createItemMacro(item, slot++, 'empoignade')
}
if (item.isCompetenceArme()) {
ui.notifications.info(`${item.name} est une compétence d'arme, la macro n'est pas liée à un arme.<br>
Créez la macro depuis l'arme ou l'onglet combat pour garder les automatisations de combat.`);
}
return return
} }
} }
@@ -51,14 +81,13 @@ export class RdDHotbar {
*/ */
static initDropbar() { static initDropbar() {
Hooks.on("hotbarDrop", (bar, documentData, slot) => { Hooks.on('hotbarDrop', (bar, documentData, slot) => {
// Create item macro if rollable item - weapon, spell, prayer, trait, or skill // Create item macro if rollable item - weapon, spell, prayer, trait, or skill
if (documentData.type == "Item") { if (documentData.type == 'Item') {
const item = fromUuidSync(documentData.uuid) ?? this.actor.items.get(documentData.uuid) const item = fromUuidSync(documentData.uuid) ?? this.actor.items.get(documentData.uuid)
console.log("DROP", documentData, item) console.log('DROP', documentData, item)
switch (item?.type ?? "") switch (item?.type) {
{
case TYPES.arme: case TYPES.arme:
case TYPES.competence: case TYPES.competence:
case TYPES.competencecreature: case TYPES.competencecreature:
@@ -72,7 +101,7 @@ export class RdDHotbar {
} }
/** Roll macro */ /** Roll macro */
static rollMacro(itemName, itemType, competenceName) { static rollMacro(itemName, itemType, categorieArme = 'competence') {
const speaker = ChatMessage.getSpeaker(); const speaker = ChatMessage.getSpeaker();
let actor; let actor;
if (speaker.token) actor = game.actors.tokens[speaker.token]; if (speaker.token) actor = game.actors.tokens[speaker.token];
@@ -88,10 +117,22 @@ export class RdDHotbar {
// Trigger the item roll // Trigger the item roll
switch (item.type) { switch (item.type) {
case TYPES.arme: case TYPES.arme:
return actor.rollArme(item, competenceName); return actor.rollArme(item, categorieArme);
case TYPES.competence: case TYPES.competence:
if (item.isCorpsACorps()) {
switch (categorieArme) {
case 'pugilat':
return actor.rollArme(RdDItemArme.mainsNues(actor), 'competence');
case 'empoignade':
return actor.rollArme(RdDItemArme.empoignade(actor), 'competence');
}
}
return actor.rollCompetence(item);
case TYPES.competencecreature: case TYPES.competencecreature:
return actor.rollCompetence(itemName); return item.system.iscombat && !item.system.isparade
? actor.rollArme(item, categorieArme)
: actor.rollCompetence(item);
} }
} }

View File

@@ -59,6 +59,7 @@ import { RdDSigneDraconiqueItemSheet } from "./item/sheet-signedraconique.js";
import { RdDItemInventaireSheet } from "./item/sheet-base-inventaire.js"; import { RdDItemInventaireSheet } from "./item/sheet-base-inventaire.js";
import { AppAstrologie } from "./sommeil/app-astrologie.js"; import { AppAstrologie } from "./sommeil/app-astrologie.js";
import { RdDItemArmure } from "./item/armure.js"; import { RdDItemArmure } from "./item/armure.js";
import { AutoAdjustDarkness as AutoAdjustDarkness } from "./time/auto-adjust-darkness.js";
/** /**
* RdD system * RdD system
@@ -182,6 +183,7 @@ export class SystemReveDeDragon {
CONFIG.Combat.documentClass = RdDCombatManager; CONFIG.Combat.documentClass = RdDCombatManager;
// préparation des différents modules // préparation des différents modules
AutoAdjustDarkness.init();
RdDTimestamp.init(); RdDTimestamp.init();
RdDCalendrier.init(); RdDCalendrier.init();
SystemCompendiums.init(); SystemCompendiums.init();

View File

@@ -50,8 +50,6 @@ export class RdDRoll extends Dialog {
encTotal: true encTotal: true
}, },
isMalusEncombrementTotal: RdDItemCompetence.isMalusEncombrementTotal(rollData.competence), isMalusEncombrementTotal: RdDItemCompetence.isMalusEncombrementTotal(rollData.competence),
malusArmureValue: actor.getMalusArmure(),
surencMalusValue: actor.computeMalusSurEncombrement(),
encTotal: actor.getEncTotal(), encTotal: actor.getEncTotal(),
ajustementAstrologique: actor.ajustementAstrologique(), ajustementAstrologique: actor.ajustementAstrologique(),
surprise: actor.getSurprise(false), surprise: actor.getSurprise(false),

View File

@@ -2,7 +2,6 @@ import { SHOW_DICE } from "./constants.js";
import { RollDataAjustements } from "./rolldata-ajustements.js"; import { RollDataAjustements } from "./rolldata-ajustements.js";
import { RdDUtility } from "./rdd-utility.js"; import { RdDUtility } from "./rdd-utility.js";
import { TMRUtility } from "./tmr-utility.js"; import { TMRUtility } from "./tmr-utility.js";
import { tmrConstants } from "./tmr-constants.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js"; import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDTMRRencontreDialog } from "./rdd-tmr-rencontre-dialog.js"; import { RdDTMRRencontreDialog } from "./rdd-tmr-rencontre-dialog.js";
import { ChatUtility } from "./chat-utility.js"; import { ChatUtility } from "./chat-utility.js";
@@ -39,14 +38,16 @@ export class RdDTMRDialog extends Dialog {
title: "Terres Médianes de Rêve", title: "Terres Médianes de Rêve",
content: html, content: html,
buttons: { buttons: {
closeButton: { label: "Fermer", callback: html => this.close(html) } closeButton: {
label: "Fermer", callback: html => this.close()
}
}, },
default: "closeButton" default: "closeButton"
} }
const dialogOptions = { const dialogOptions = {
classes: ["tmrdialog"], classes: ["tmrdialog"],
width: 920, height: 980, width: 920, maxheight: 1024, height: 'fit-content',
'z-index': 40 'z-index': 40
} }
super(dialogConf, dialogOptions); super(dialogConf, dialogOptions);
@@ -62,8 +63,8 @@ export class RdDTMRDialog extends Dialog {
this.allTokens = []; this.allTokens = [];
this.rencontreState = 'aucune'; this.rencontreState = 'aucune';
this.pixiApp = new PIXI.Application({ width: 720, height: 860 }); this.pixiApp = new PIXI.Application({ width: 720, height: 860 });
this.pixiTMR = new PixiTMR(this, this.pixiApp); this.pixiTMR = new PixiTMR(this, this.pixiApp);
this.subdialog = undefined
this.callbacksOnAnimate = []; this.callbacksOnAnimate = [];
if (!this.viewOnly) { if (!this.viewOnly) {
@@ -74,6 +75,31 @@ export class RdDTMRDialog extends Dialog {
this.pixiTMR.load((loader, resources) => this.createPixiSprites()); this.pixiTMR.load((loader, resources) => this.createPixiSprites());
} }
async forceTMRDisplay() {
this.bringToTop();
if (this.subdialog) {
this.subdialog.bringToTop();
}
}
async restoreTMRAfterAction() {
this.subdialog = undefined
await this.maximize();
this.bringToTop();
}
forceTMRContinueAction() {
ui.notifications.warn('Vous devez finir votre action avant de continuer dans les TMR');
this.subdialog.bringToTop();
return;
}
setTMRPendingAction(dialog) {
this.subdialog = dialog
if (dialog instanceof Application) {
dialog.bringToTop();
}
}
isDemiReveCache() { isDemiReveCache() {
return !game.user.isGM && this.actor.isTMRCache(); return !game.user.isGM && this.actor.isTMRCache();
} }
@@ -175,6 +201,9 @@ export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
async moveFromKey(move) { async moveFromKey(move) {
if (this.subdialog) {
return this.forceTMRContinueAction();
}
let oddq = TMRUtility.coordTMRToOddq(this._getActorCoord()); let oddq = TMRUtility.coordTMRToOddq(this._getActorCoord());
if (move == 'top') oddq.row -= 1; if (move == 'top') oddq.row -= 1;
@@ -199,7 +228,9 @@ export class RdDTMRDialog extends Dialog {
super.activateListeners(html); super.activateListeners(html);
this.html = html; this.html = html;
document.getElementById("tmrrow1").insertCell(0).append(this.pixiApp.view); document.getElementsByClassName("tmr-row")
.item(0)
.insertCell(0).append(this.pixiApp.view);
if (this.viewOnly) { if (this.viewOnly) {
this.html.find('.lancer-sort').remove(); this.html.find('.lancer-sort').remove();
@@ -210,6 +241,10 @@ export class RdDTMRDialog extends Dialog {
HtmlUtility.showControlWhen(this.html.find(".appliquerFatigue"), ReglesOptionnelles.isUsing("appliquer-fatigue")); HtmlUtility.showControlWhen(this.html.find(".appliquerFatigue"), ReglesOptionnelles.isUsing("appliquer-fatigue"));
HtmlUtility.showControlWhen(this.html.find(".lire-signe-draconique"), this.actor.isResonanceSigneDraconique(this._getActorCoord())); HtmlUtility.showControlWhen(this.html.find(".lire-signe-draconique"), this.actor.isResonanceSigneDraconique(this._getActorCoord()));
this.html.find('tr.tmr-row *').click((event) => {
this.subdialog?.bringToTop();
});
// Roll Sort // Roll Sort
this.html.find('.lancer-sort').click((event) => { this.html.find('.lancer-sort').click((event) => {
this.actor.rollUnSort(this._getActorCoord()); this.actor.rollUnSort(this._getActorCoord());
@@ -231,7 +266,6 @@ export class RdDTMRDialog extends Dialog {
this.cumulFatigue += this.fatigueParCase; this.cumulFatigue += this.fatigueParCase;
} }
await this.actor.reveActuelIncDec(reveCout); await this.actor.reveActuelIncDec(reveCout);
// Le reste... // Le reste...
this.updateValuesDisplay(); this.updateValuesDisplay();
let tmr = TMRUtility.getTMR(this._getActorCoord()); let tmr = TMRUtility.getTMR(this._getActorCoord());
@@ -271,6 +305,10 @@ export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
async close() { async close() {
if (this.subdialog) {
return this.forceTMRContinueAction()
}
this.descenteTMR = true; this.descenteTMR = true;
if (this.actor.tmrApp) { if (this.actor.tmrApp) {
this.actor.tmrApp = undefined; // Cleanup reference this.actor.tmrApp = undefined; // Cleanup reference
@@ -293,6 +331,7 @@ export class RdDTMRDialog extends Dialog {
switch (action) { switch (action) {
case 'derober': case 'derober':
await this.derober(); await this.derober();
this.restoreTMRAfterAction();
return; return;
case 'refouler': case 'refouler':
await this.refouler(); await this.refouler();
@@ -305,6 +344,7 @@ export class RdDTMRDialog extends Dialog {
break; break;
} }
await this.postRencontre(tmr); await this.postRencontre(tmr);
this.restoreTMRAfterAction();
} }
async derober() { async derober() {
@@ -360,7 +400,6 @@ export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
checkQuitterTMR() { checkQuitterTMR() {
if (this.actor.isDead()) { if (this.actor.isDead()) {
this._tellToGM("Vous êtes mort : vous quittez les Terres médianes !"); this._tellToGM("Vous êtes mort : vous quittez les Terres médianes !");
this.close(); this.close();
@@ -531,8 +570,9 @@ export class RdDTMRDialog extends Dialog {
await this.maitriserRencontre(); await this.maitriserRencontre();
} }
else { else {
let dialog = new RdDTMRRencontreDialog(this, this.currentRencontre, tmr); const dialog = new RdDTMRRencontreDialog(this.actor, this.currentRencontre, tmr);
dialog.render(true); dialog.render(true);
this.setTMRPendingAction(dialog);
} }
} }
else { else {
@@ -544,9 +584,12 @@ export class RdDTMRDialog extends Dialog {
_presentCite(tmr) { _presentCite(tmr) {
const presentCite = this.casesSpeciales.find(c => EffetsDraconiques.presentCites.isCase(c, tmr.coord)); const presentCite = this.casesSpeciales.find(c => EffetsDraconiques.presentCites.isCase(c, tmr.coord));
if (presentCite) { if (presentCite) {
this.minimize();
const caseData = presentCite; const caseData = presentCite;
EffetsDraconiques.presentCites.choisirUnPresent(caseData, (present => this._utiliserPresentCite(presentCite, present, tmr))); const dialog = EffetsDraconiques.presentCites.choisirUnPresent(caseData, present => {
this._utiliserPresentCite(presentCite, present, tmr)
this.restoreTMRAfterAction();
});
this.setTMRPendingAction(dialog);
} }
return presentCite; return presentCite;
} }
@@ -572,8 +615,6 @@ export class RdDTMRDialog extends Dialog {
presentCite: presentCite presentCite: presentCite
}; };
await this._tentativeMaitrise(rencontreData); await this._tentativeMaitrise(rencontreData);
this.maximize();
this.postRencontre(tmr); this.postRencontre(tmr);
} }
@@ -587,7 +628,10 @@ export class RdDTMRDialog extends Dialog {
? TMRUtility.getTMRType(tmr.coord) + " ??" ? TMRUtility.getTMRType(tmr.coord) + " ??"
: tmr.label + " (" + tmr.coord + ")"); : tmr.label + " (" + tmr.coord + ")");
const fakeDialogRencontre = { bringToTop: () => { } };
this.setTMRPendingAction(fakeDialogRencontre)
let myRoll = await RdDDice.rollTotal("1dt", { showDice: SHOW_DICE }); let myRoll = await RdDDice.rollTotal("1dt", { showDice: SHOW_DICE });
this.restoreTMRAfterAction()
if (myRoll == 7) { if (myRoll == 7) {
this._tellToUser(myRoll + ": Rencontre en " + locTMR); this._tellToUser(myRoll + ": Rencontre en " + locTMR);
return await game.system.rdd.rencontresTMR.getRencontreAleatoire(tmr, this.actor.isMauvaiseRencontre()) return await game.system.rdd.rencontresTMR.getRencontreAleatoire(tmr, this.actor.isMauvaiseRencontre())
@@ -777,22 +821,22 @@ export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
async _maitriserTMR(rollData, callbackMaitrise) { async _maitriserTMR(rollData, callbackMaitrise) {
this.minimize(); // Hide
rollData.isTMRCache = rollData.actor.isTMRCache(); rollData.isTMRCache = rollData.actor.isTMRCache();
const dialog = await RdDRoll.create(this.actor, rollData, const dialog = await RdDRoll.create(this.actor, rollData,
{ {
html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-maitrise-tmr.html', html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-maitrise-tmr.html',
close: html => { this.maximize(); } // Re-display TMR
}, },
{ {
name: rollData.maitrise.verbe, label: rollData.maitrise.action, name: rollData.maitrise.verbe, label: rollData.maitrise.action,
callbacks: [ callbacks: [
this.actor.createCallbackExperience(), this.actor.createCallbackExperience(),
{ action: r => { this.restoreTMRAfterAction() } },
{ action: callbackMaitrise } { action: callbackMaitrise }
] ]
} }
); );
dialog.render(true); dialog.render(true);
this.setTMRPendingAction(dialog);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -862,7 +906,8 @@ export class RdDTMRDialog extends Dialog {
nettoyerRencontre() { nettoyerRencontre() {
if (!this.currentRencontre) return; // Sanity check if (!this.currentRencontre) return; // Sanity check
if (this.currentRencontre.graphics) { if (this.currentRencontre.graphics) {
for (let drawRect of this.currentRencontre.graphics) { // Suppression des dessins des zones possibles for (let drawRect of this.currentRencontre.graphics) {
// Suppression des dessins des zones possibles
this.pixiApp.stage.removeChild(drawRect); this.pixiApp.stage.removeChild(drawRect);
} }
} }
@@ -895,8 +940,8 @@ export class RdDTMRDialog extends Dialog {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
isConnaissanceFleuve(currentTMR, nextTMR) { isConnaissanceFleuve(tmrApp, nextTMR) {
return TMRUtility.getTMR(currentTMR).type == 'fleuve' && return TMRUtility.getTMR(tmrApp).type == 'fleuve' &&
TMRUtility.getTMR(nextTMR).type == 'fleuve' && TMRUtility.getTMR(nextTMR).type == 'fleuve' &&
EffetsDraconiques.isConnaissanceFleuve(this.actor); EffetsDraconiques.isConnaissanceFleuve(this.actor);
} }
@@ -906,15 +951,15 @@ export class RdDTMRDialog extends Dialog {
if (this.viewOnly) { if (this.viewOnly) {
return; return;
} }
let clickOddq = RdDTMRDialog._computeEventOddq(event.nativeEvent); if (this.subdialog) {
await this._onClickTMRPos(clickOddq); // Vérifier l'état des compteurs reve/fatigue/vie return this.forceTMRContinueAction()
} }
let clickOddq = TMRUtility.computeEventOddq(event);
/* -------------------------------------------- */
async _onClickTMRPos(clickOddq) {
let currentOddq = TMRUtility.coordTMRToOddq(this._getActorCoord()); let currentOddq = TMRUtility.coordTMRToOddq(this._getActorCoord());
let targetCoord = TMRUtility.oddqToCoordTMR(clickOddq); let targetCoord = TMRUtility.oddqToCoordTMR(clickOddq);
let currentCoord = TMRUtility.oddqToCoordTMR(currentOddq); let currentCoord = TMRUtility.oddqToCoordTMR(currentOddq);
// Validation de la case de destination (gestion du cas des rencontres qui peuvent téléporter) // Validation de la case de destination (gestion du cas des rencontres qui peuvent téléporter)
let deplacementType = this._calculDeplacement(targetCoord, currentCoord, currentOddq, clickOddq); let deplacementType = this._calculDeplacement(targetCoord, currentCoord, currentOddq, clickOddq);
@@ -946,7 +991,7 @@ export class RdDTMRDialog extends Dialog {
await this._messagerDemiReve(targetCoord); await this._messagerDemiReve(targetCoord);
break; break;
default: 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"); ui.notifications.error("Vous ne pouvez 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); console.log("STATUS :", this.rencontreState, this.currentRencontre);
} }
@@ -975,9 +1020,11 @@ export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
async _messagerDemiReve(targetCoord) { async _messagerDemiReve(targetCoord) {
/* /*
TODO: si la case a un sort en réserve, lancer ce sort. TODO:
Si la case a un sort en réserve, lancer ce sort.
Si la case est le demi-rêve, ne pas lancer de sort. Si la case est le demi-rêve, ne pas lancer de sort.
Si un lancement de sort est en cours, trouver un moyen de réafficher cette fenêtre si on essaie de lancer un sort (ou bloquer le lancer de sort) Si un lancement de sort est en cours, trouver un moyen de réafficher cette fenêtre
si on essaie de lancer un sort (ou bloquer le lancer de sort)
*/ */
this.notifierResonanceSigneDraconique(targetCoord); this.notifierResonanceSigneDraconique(targetCoord);
await this.actor.rollUnSort(targetCoord); await this.actor.rollUnSort(targetCoord);
@@ -994,6 +1041,9 @@ export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
async _deplacerDemiReve(targetCoord, deplacementType) { async _deplacerDemiReve(targetCoord, deplacementType) {
if (this.subdialog) {
return this.forceTMRContinueAction()
}
if (this.currentRencontre != 'normal') { if (this.currentRencontre != 'normal') {
this.nettoyerRencontre(); this.nettoyerRencontre();
} }
@@ -1043,25 +1093,16 @@ export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
async positionnerDemiReve(coord) { async positionnerDemiReve(coord) {
if (this.subdialog) {
return this.forceTMRContinueAction()
}
await this.actor.updateCoordTMR(coord); await this.actor.updateCoordTMR(coord);
this.forceDemiRevePositionView(); this.forceDemiRevePositionView();
let tmr = TMRUtility.getTMR(coord); let tmr = TMRUtility.getTMR(coord);
await this.postRencontre(tmr); await this.postRencontre(tmr);
return tmr; return tmr;
} }
/* -------------------------------------------- */
static _computeEventOddq(origEvent) {
console.log("EVENT", origEvent)
let canvasRect = origEvent.target.getBoundingClientRect();
let x = origEvent.clientX - canvasRect.left;
let y = origEvent.clientY - canvasRect.top;
let col = Math.floor(x / tmrConstants.cellw); // [From 0 -> 12]
y -= col % 2 == 0 ? tmrConstants.col1_y : tmrConstants.col2_y;
let row = Math.floor(y / tmrConstants.cellh); // [From 0 -> 14]
return { col: col, row: row };
}
/* -------------------------------------------- */ /* -------------------------------------------- */
/** Retourne les coordonnées x, h, w, h du rectangle d'une case donnée */ /** Retourne les coordonnées x, h, w, h du rectangle d'une case donnée */
_getCaseRectangleCoord(coord) { _getCaseRectangleCoord(coord) {

View File

@@ -2,7 +2,7 @@
export class RdDTMRRencontreDialog extends Dialog { export class RdDTMRRencontreDialog extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
constructor(tmrApp, rencontre, tmr) { constructor(actor, rencontre, tmr) {
const dialogConf = { const dialogConf = {
title: "Rencontre en TMR!", title: "Rencontre en TMR!",
content: "Vous rencontrez un " + rencontre.name + " de force " + rencontre.system.force + "<br>", content: "Vous rencontrez un " + rencontre.name + " de force " + rencontre.system.force + "<br>",
@@ -28,23 +28,30 @@ export class RdDTMRRencontreDialog extends Dialog {
this.toClose = false; this.toClose = false;
this.tmr = tmr; this.tmr = tmr;
this.tmrApp = tmrApp; this.actor = actor;
this.rencontre = rencontre; this.rencontre = rencontre;
this.tmrApp.minimize();
} }
async onButtonAction(action) { async onButtonAction(action) {
this.toClose = true; this.toClose = true;
this.tmrApp.onActionRencontre(action, this.tmr, this.rencontre) await this.actor.tmrApp?.restoreTMRAfterAction();
this.actor.tmrApp?.onActionRencontre(action, this.tmr, this.rencontre)
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
close() { async close() {
if (this.actor.tmrApp){
if (this.toClose) { if (this.toClose) {
this.tmrApp.maximize(); return await super.close();
return super.close();
} }
else {
ui.notifications.info("Vous devez résoudre la rencontre."); ui.notifications.info("Vous devez résoudre la rencontre.");
return this.actor.tmrApp.forceTMRContinueAction();
}
}
else {
return await super.close();
}
} }
} }

View File

@@ -69,8 +69,8 @@ export const referenceAjustements = {
getValue: (rollData, actor) => -actor.getEncTotal() getValue: (rollData, actor) => -actor.getEncTotal()
}, },
surenc: { surenc: {
isVisible: (rollData, actor) => actor.isSurenc(), isVisible: (rollData, actor) => RdDCarac.isActionPhysique(rollData.selectedCarac) && actor.isSurenc(),
isUsed: (rollData, actor) => rollData.use?.surenc, isUsed: (rollData, actor) => rollData.use?.surenc && RdDCarac.isActionPhysique(rollData.selectedCarac),
getLabel: (rollData, actor) => 'Sur-encombrement', getLabel: (rollData, actor) => 'Sur-encombrement',
getValue: (rollData, actor) => actor.computeMalusSurEncombrement() getValue: (rollData, actor) => actor.computeMalusSurEncombrement()
}, },

View File

@@ -128,7 +128,7 @@ export class AppAstrologie extends Application {
this.selectHeureNaissance(event.currentTarget.attributes['data-heure-naissance'].value); this.selectHeureNaissance(event.currentTarget.attributes['data-heure-naissance'].value);
}) })
this.html.find('[name="jet-astrologie"]').click(event => this.requestJetAstrologie()); this.html.find('[name="jet-astrologie"]').click(event => this.requestJetAstrologie());
this.html.find('[name="rebuild-nombres-astraux"]').click(event => this.rebuildNombresAstraux()); this.html.find('[name="rebuild-nombres-astraux"]').click(event => this.onRebuild());
this.onCalculThemeAstral(); this.onCalculThemeAstral();
} }
@@ -144,7 +144,7 @@ export class AppAstrologie extends Application {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async rebuildNombresAstraux() { async onRebuild() {
game.system.rdd.calendrier.resetNombresAstraux(); game.system.rdd.calendrier.resetNombresAstraux();
await game.system.rdd.calendrier.rebuildNombresAstraux(); await game.system.rdd.calendrier.rebuildNombresAstraux();

View File

@@ -0,0 +1,34 @@
import { SYSTEM_RDD } from "../constants.js";
export const AUTO_ADJUST_DARKNESS = "auto-adjust-darkness";
export class AutoAdjustDarkness {
static init() {
game.settings.register(SYSTEM_RDD, AUTO_ADJUST_DARKNESS, {
name: AUTO_ADJUST_DARKNESS,
scope: "world",
config: false,
default: true,
type: Boolean
});
}
static async adjust(darkness) {
if (AutoAdjustDarkness.isAuto()) {
const scene = game.scenes.viewed;
if (scene.globalLight && scene.tokenVision) {
await scene.update({ darkness });
}
}
}
static isAuto() {
return game.settings.get(SYSTEM_RDD, AUTO_ADJUST_DARKNESS);
}
static async toggle() {
const previous = AutoAdjustDarkness.isAuto();
await game.settings.set(SYSTEM_RDD, AUTO_ADJUST_DARKNESS, !previous)
}
}

View File

@@ -5,10 +5,11 @@ import { RdDUtility } from "../rdd-utility.js";
import { RdDDice } from "../rdd-dice.js"; import { RdDDice } from "../rdd-dice.js";
import { Misc } from "../misc.js"; import { Misc } from "../misc.js";
import { DialogChronologie } from "../dialog-chronologie.js"; import { DialogChronologie } from "../dialog-chronologie.js";
import { HIDE_DICE, SHOW_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "../constants.js"; import { HIDE_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "../constants.js";
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js"; import { ReglesOptionnelles } from "../settings/regles-optionnelles.js";
import { DialogChateauDormant } from "../sommeil/dialog-chateau-dormant.js"; import { DialogChateauDormant } from "../sommeil/dialog-chateau-dormant.js";
import { APP_ASTROLOGIE_REFRESH, AppAstrologie } from "../sommeil/app-astrologie.js"; import { APP_ASTROLOGIE_REFRESH, AppAstrologie } from "../sommeil/app-astrologie.js";
import { AutoAdjustDarkness } from "./auto-adjust-darkness.js";
const TEMPLATE_CALENDRIER = "systems/foundryvtt-reve-de-dragon/templates/time/calendar.hbs"; const TEMPLATE_CALENDRIER = "systems/foundryvtt-reve-de-dragon/templates/time/calendar.hbs";
@@ -51,7 +52,7 @@ export class RdDCalendrier extends Application {
if (Misc.isUniqueConnectedGM()) { // Uniquement si GM if (Misc.isUniqueConnectedGM()) { // Uniquement si GM
RdDTimestamp.setWorldTime(this.timestamp); RdDTimestamp.setWorldTime(this.timestamp);
this.nombresAstraux = this.getNombresAstraux(); this.nombresAstraux = this.getNombresAstraux();
this.rebuildNombresAstraux(HIDE_DICE); // Ensure always up-to-date this.rebuildNombresAstraux(); // Ensure always up-to-date
} }
Hooks.on('updateSetting', async (setting, update, options, id) => this.onUpdateSetting(setting, update, options, id)); Hooks.on('updateSetting', async (setting, update, options, id) => this.onUpdateSetting(setting, update, options, id));
} }
@@ -84,26 +85,20 @@ export class RdDCalendrier extends Application {
} }
display() { display() {
AutoAdjustDarkness.adjust(RdDTimestamp.getWorldTime().darkness);
const pos = this.getSavePosition() const pos = this.getSavePosition()
this.render(true, { left: pos.left, top: pos.top }); this.render(true, { left: pos.left, top: pos.top });
return this; return this;
} }
_getHeaderButtons() { _getHeaderButtons() {
const buttons = [];
if (game.user.isGM) { if (game.user.isGM) {
buttons.unshift({ return [
class: "calendar-astrologie", { class: "calendar-astrologie", icon: "fa-solid fa-moon-over-sun", onclick: ev => this.showAstrologieEditor() },
icon: "fa-solid fa-moon-over-sun", { class: "calendar-set-datetime", icon: "fa-solid fa-calendar-pen", onclick: ev => this.showCalendarEditor() },
onclick: ev => this.showAstrologieEditor() ]
},
{
class: "calendar-set-datetime",
icon: "fa-solid fa-calendar-pen",
onclick: ev => this.showCalendarEditor()
});
} }
return buttons return []
} }
async close() { } async close() { }
@@ -129,6 +124,7 @@ export class RdDCalendrier extends Application {
formData.isGM = game.user.isGM; formData.isGM = game.user.isGM;
formData.heures = RdDTimestamp.definitions() formData.heures = RdDTimestamp.definitions()
formData.horlogeAnalogique = this.horlogeAnalogique; formData.horlogeAnalogique = this.horlogeAnalogique;
formData.autoDarkness = AutoAdjustDarkness.isAuto()
return formData; return formData;
} }
@@ -139,6 +135,7 @@ export class RdDCalendrier extends Application {
this.html = html; this.html = html;
this.html.find('.ajout-chronologie').click(ev => DialogChronologie.create()); this.html.find('.ajout-chronologie').click(ev => DialogChronologie.create());
this.html.find('.toggle-horloge-analogique').click(ev => this.onToggleHorlogeAnalogique()) this.html.find('.toggle-horloge-analogique').click(ev => this.onToggleHorlogeAnalogique())
this.html.find('.toggle-auto-darkness').click(ev => this.onToggleAutoDarkness())
this.html.find('.calendar-btn').click(ev => this.onCalendarButton(ev)); this.html.find('.calendar-btn').click(ev => this.onCalendarButton(ev));
this.html.find('.horloge-roue .horloge-heure').click(event => { this.html.find('.horloge-roue .horloge-heure').click(event => {
const h = this.html.find(event.currentTarget)?.data('heure'); const h = this.html.find(event.currentTarget)?.data('heure');
@@ -224,15 +221,8 @@ export class RdDCalendrier extends Application {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async ajouterNombreAstral(indexDate, showDice = SHOW_DICE) { async ajouterNombreAstral(indexDate) {
const nombreAstral = await RdDDice.rollTotal("1dh", { showDice: showDice, rollMode: "selfroll" }); const nombreAstral = await RdDDice.rollTotal("1dh", { showDice: HIDE_DICE, rollMode: "selfroll" });
const dateFuture = RdDTimestamp.formatIndexDate(indexDate);
if (showDice != HIDE_DICE) {
ChatMessage.create({
whisper: ChatMessage.getWhisperRecipients("GM"),
content: `Le chiffre astrologique du ${dateFuture} sera le ${nombreAstral}`
});
}
return { return {
nombreAstral: nombreAstral, nombreAstral: nombreAstral,
valeursFausses: [], valeursFausses: [],
@@ -267,9 +257,8 @@ export class RdDCalendrier extends Application {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async rebuildNombresAstraux(showDice = HIDE_DICE) { async rebuildNombresAstraux() {
if (Misc.isUniqueConnectedGM()) { if (Misc.isUniqueConnectedGM()) {
console.log("Astral rebuild")
let newList = []; let newList = [];
for (let i = 0; i < MAX_NOMBRE_ASTRAL; i++) { for (let i = 0; i < MAX_NOMBRE_ASTRAL; i++) {
let dayIndex = this.timestamp.indexDate + i; let dayIndex = this.timestamp.indexDate + i;
@@ -277,7 +266,7 @@ export class RdDCalendrier extends Application {
if (na) { if (na) {
newList[i] = na; newList[i] = na;
} else { } else {
newList[i] = await this.ajouterNombreAstral(dayIndex, showDice); newList[i] = await this.ajouterNombreAstral(dayIndex);
} }
} }
this.nombresAstraux = newList; this.nombresAstraux = newList;
@@ -375,7 +364,7 @@ export class RdDCalendrier extends Application {
if (request.rolled.isSuccess) { if (request.rolled.isSuccess) {
if (request.rolled.isPart) { if (request.rolled.isPart) {
// Gestion expérience (si existante) // Gestion expérience (si existante)
request.competence = actor.getCompetence("astrologie") request.competence = actor.getCompetence('Astrologie')
request.selectedCarac = actor.system.carac["vue"]; request.selectedCarac = actor.system.carac["vue"];
actor.appliquerAjoutExperience(request, 'hide'); actor.appliquerAjoutExperience(request, 'hide');
} }
@@ -447,4 +436,9 @@ export class RdDCalendrier extends Application {
async showAstrologieEditor() { async showAstrologieEditor() {
await AppAstrologie.create(); await AppAstrologie.create();
} }
async onToggleAutoDarkness() {
await AutoAdjustDarkness.toggle()
this.display()
}
} }

View File

@@ -2,6 +2,7 @@ import { SHOW_DICE, SYSTEM_RDD } from "../constants.js";
import { Grammar } from "../grammar.js"; import { Grammar } from "../grammar.js";
import { Misc } from "../misc.js"; import { Misc } from "../misc.js";
import { RdDDice } from "../rdd-dice.js"; import { RdDDice } from "../rdd-dice.js";
import { AutoAdjustDarkness } from "./auto-adjust-darkness.js";
export const WORLD_TIMESTAMP_SETTING = "calendrier"; export const WORLD_TIMESTAMP_SETTING = "calendrier";
@@ -15,18 +16,18 @@ export const RDD_MINUTES_PAR_JOUR = 1440; //RDD_HEURES_PAR_JOUR * RDD_MINUTES_PA
const ROUNDS_PAR_MINUTE = 10; const ROUNDS_PAR_MINUTE = 10;
const DEFINITION_HEURES = [ const DEFINITION_HEURES = [
{ key: "vaisseau", label: "Vaisseau", lettreFont: 'v', saison: "Printemps" }, { key: "vaisseau", label: "Vaisseau", lettreFont: 'v', saison: "Printemps" , darkness: 0.7},
{ key: "sirene", label: "Sirène", lettreFont: 'i', saison: "Printemps" }, { key: "sirene", label: "Sirène", lettreFont: 'i', saison: "Printemps" , darkness: 0.4},
{ key: "faucon", label: "Faucon", lettreFont: 'f', saison: "Printemps" }, { key: "faucon", label: "Faucon", lettreFont: 'f', saison: "Printemps" , darkness: 0},
{ key: "couronne", label: "Couronne", lettreFont: '', saison: "Eté" }, { key: "couronne", label: "Couronne", lettreFont: '', saison: "Eté" , darkness: 0},
{ key: "dragon", label: "Dragon", lettreFont: 'd', saison: "Eté" }, { key: "dragon", label: "Dragon", lettreFont: 'd', saison: "Eté", darkness: 0 },
{ key: "epees", label: "Epées", lettreFont: 'e', saison: "Eté" }, { key: "epees", label: "Epées", lettreFont: 'e', saison: "Eté", darkness: 0},
{ key: "lyre", label: "Lyre", lettreFont: 'l', saison: "Automne" }, { key: "lyre", label: "Lyre", lettreFont: 'l', saison: "Automne", darkness: 0.4 },
{ key: "serpent", label: "Serpent", lettreFont: 's', saison: "Automne" }, { key: "serpent", label: "Serpent", lettreFont: 's', saison: "Automne", darkness: 0.7 },
{ key: "poissonacrobate", label: "Poisson Acrobate", lettreFont: 'p', saison: "Automne" }, { key: "poissonacrobate", label: "Poisson Acrobate", lettreFont: 'p', saison: "Automne", darkness: 1 },
{ key: "araignee", label: "Araignée", lettreFont: 'a', saison: "Hiver" }, { key: "araignee", label: "Araignée", lettreFont: 'a', saison: "Hiver", darkness: 1 },
{ key: "roseau", label: "Roseau", lettreFont: 'r', saison: "Hiver" }, { key: "roseau", label: "Roseau", lettreFont: 'r', saison: "Hiver", darkness: 1 },
{ key: "chateaudormant", label: "Château Dormant", lettreFont: 'c', saison: "Hiver" }, { key: "chateaudormant", label: "Château Dormant", lettreFont: 'c', saison: "Hiver", darkness: 1 },
] ]
const FORMULES_DUREE = [ const FORMULES_DUREE = [
@@ -58,6 +59,7 @@ export class RdDTimestamp {
type: Object type: Object
}); });
for (let i = 0; i < DEFINITION_HEURES.length; i++) { for (let i = 0; i < DEFINITION_HEURES.length; i++) {
DEFINITION_HEURES[i].heure = i; DEFINITION_HEURES[i].heure = i;
DEFINITION_HEURES[i].hh = RdDTimestamp.hh(i); DEFINITION_HEURES[i].hh = RdDTimestamp.hh(i);
@@ -66,7 +68,6 @@ export class RdDTimestamp {
} }
} }
static hh(heure) { static hh(heure) {
return heure < 9 ? `0${heure + 1}` : `${heure + 1}`; return heure < 9 ? `0${heure + 1}` : `${heure + 1}`;
} }
@@ -239,6 +240,13 @@ export class RdDTimestamp {
get angleHeure() { return this.indexMinute / RDD_MINUTES_PAR_JOUR * 360 - 45 } get angleHeure() { return this.indexMinute / RDD_MINUTES_PAR_JOUR * 360 - 45 }
get angleMinute() { return this.indexMinute / RDD_MINUTES_PAR_HEURES * 360 + 45 } get angleMinute() { return this.indexMinute / RDD_MINUTES_PAR_HEURES * 360 + 45 }
get darkness() {
const darknessDebut = RdDTimestamp.definition(this.heure).darkness *100
const darknessFin = RdDTimestamp.definition(this.heure + 1).darkness *100
const darknessMinute = Math.round((darknessFin - darknessDebut) * this.minute / RDD_MINUTES_PAR_HEURES);
return (darknessDebut + darknessMinute)/100
}
/** /**
* Convertit le timestamp en une structure avec les informations utiles * Convertit le timestamp en une structure avec les informations utiles
* pour afficher la date et l'heure * pour afficher la date et l'heure

View File

@@ -1,6 +1,7 @@
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { Grammar } from "./grammar.js"; import { Grammar } from "./grammar.js";
import { RdDDice } from "./rdd-dice.js"; import { RdDDice } from "./rdd-dice.js";
import { tmrConstants } from "./tmr-constants.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
const TMRMapping = { const TMRMapping = {
@@ -163,7 +164,7 @@ const TMRMapping = {
C12: { type: "lac", label: "Lac de Fricassa" }, C12: { type: "lac", label: "Lac de Fricassa" },
D12: { type: "collines", label: "Collines dHuaï" }, D12: { type: "collines", label: "Collines dHuaï" },
E12: { type: "monts", label: "Monts Ajourés" }, E12: { type: "monts", label: "Monts Ajourés" },
F12: { type: "necropole", label: "Nécropole de Troat" }, F12: { type: "necropole", label: "Nécropole de Throat" },
G12: { type: "plaines", label: "Plaines de Lufmil" }, G12: { type: "plaines", label: "Plaines de Lufmil" },
H12: { type: "collines", label: "Collines de Tooth" }, H12: { type: "collines", label: "Collines de Tooth" },
I12: { type: "gouffre", label: "Gouffre Abimeux" }, I12: { type: "gouffre", label: "Gouffre Abimeux" },
@@ -375,6 +376,36 @@ export class TMRUtility {
return caseList; return caseList;
} }
// /* -------------------------------------------- */
static computeEventPosition(event) {
if (!event.nativeEvent.target.getBoundingClientRect) {
return { x: 0, y: 0 }
}
const canvasRect = event.nativeEvent.target.getBoundingClientRect();
return {
x: event.nativeEvent.clientX - canvasRect.left,
y: event.nativeEvent.clientY - canvasRect.top
};
}
/* -------------------------------------------- */
static computeEventOddq(event) {
var { x, y } = TMRUtility.computeEventPosition(event);
return TMRUtility.computeOddq(x, y);
}
static computeOddq(x, y) {
const col = Math.floor(x / tmrConstants.cellw); // [From 0 -> 12]
const decallageColonne = col % 2 == 0 ? tmrConstants.col1_y : tmrConstants.col2_y;
const row = Math.floor((y - decallageColonne) / tmrConstants.cellh); // [From 0 -> 14]
return { col, row };
}
static computeEventCoord(event) {
const oddq = TMRUtility.computeEventOddq(event);
return TMRUtility.oddqToCoordTMR(oddq);
}
/* -------------------------------------------- */ /* -------------------------------------------- */
// https://www.redblobgames.com/grids/hexagons/#distances // https://www.redblobgames.com/grids/hexagons/#distances
// TMR Letter-row correspond to "odd-q" grid (letter => col, numeric => row ) // TMR Letter-row correspond to "odd-q" grid (letter => col, numeric => row )

View File

@@ -4,7 +4,6 @@ import { PixiTMR } from "./pixi-tmr.js";
export class CarteTmr extends Draconique { export class CarteTmr extends Draconique {
constructor() { constructor() {
console.log("Sprite create 1!!!!")
super(); super();
} }
@@ -14,9 +13,25 @@ export class CarteTmr extends Draconique {
async onActorCreateOwned(actor, item) { } async onActorCreateOwned(actor, item) { }
code() { return 'tmr' } code() { return 'tmr' }
img() { return 'systems/foundryvtt-reve-de-dragon/styles/img/ui/tmp_main_r1.webp' } img() { return 'systems/foundryvtt-reve-de-dragon/styles/img/ui/tmr.webp' }
createSprite(pixiTMR) { createSprite(pixiTMR) {
return pixiTMR.carteTmr(this.code());
const img = PixiTMR.getImgFromCode(this.code())
const sprite = new PIXI.Sprite(PIXI.utils.TextureCache[img]);
// Setup the position of the TMR
sprite.x = 0;
sprite.y = 0;
sprite.width = 722;
sprite.height = 860;
// Rotate around the center
sprite.anchor.set(0);
sprite.buttonMode = true;
sprite.tmrObject = pixiTMR;
pixiTMR.addTooltip(sprite, (e,s) => this.computeTooltip(e,s));
pixiTMR.pixiApp.stage.addChild(sprite);
return sprite;
} }
} }

View File

@@ -82,7 +82,7 @@ export class Draconique {
img() { return undefined } img() { return undefined }
/** /**
* factory d'élément graphique PIXI correpsondant à l'objet draconique * factory d'élément graphique PIXI correspondant à l'objet draconique
* @param {*} pixiTMR instance de PixiTMR qui gère les tooltips, les méthodes de création de sprite standard, les clicks. * @param {*} pixiTMR instance de PixiTMR qui gère les tooltips, les méthodes de création de sprite standard, les clicks.
*/ */
token(pixiTMR, linkData, coordTMR, type = undefined) { token(pixiTMR, linkData, coordTMR, type = undefined) {
@@ -91,12 +91,32 @@ export class Draconique {
coordTMR: coordTMR coordTMR: coordTMR
}; };
token[type ?? this.code()] = linkData; token[type ?? this.code()] = linkData;
console.log("SPRITE: ", token.sprite) this.linkData = linkData;
//PixiTMR.getImgFromCode() if (this.tooltip(linkData)) {
pixiTMR.addTooltip(token.sprite, this.tooltip(linkData)); pixiTMR.addTooltip(token.sprite, (e, s) => this.computeTooltip(e, s));
}
return token; return token;
} }
/**
* methode en charge de recalculer le tooltip lorsque la souris bouge
* @param {*} event evenement contenant les coordonnées
* @param {*} sprite sprite pour laquelle calculer le tooltip
*/
computeTooltip(event, sprite) {
if (sprite.isOver) {
const oddq = TMRUtility.computeEventOddq(event);
const coord = TMRUtility.oddqToCoordTMR(oddq);
const tmr = TMRUtility.getTMR(coord)
if (tmr){
const label = TMRUtility.getTMRLabel(coord);
const text = this.tooltip(this.linkData);
return text ? `${coord}: ${label}\n${text}` : `${coord}: ${label}`
}
}
return '';
}
/** /**
* factory d'élément graphique PIXI correpsondant à l'objet draconique * 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. * @param {*} pixiTMR instance de PixiTMR qui gère les tooltips, les méthodes de création de sprite standard, les clicks.

View File

@@ -1,6 +1,8 @@
import { RdDTMRDialog } from "../rdd-tmr-dialog.js";
import { tmrConstants, tmrTokenZIndex } from "../tmr-constants.js"; import { tmrConstants, tmrTokenZIndex } from "../tmr-constants.js";
import { TMRUtility } from "../tmr-utility.js";
const tooltipStyle = new PIXI.TextStyle({ export const tooltipStyle = new PIXI.TextStyle({
fontFamily: 'CaslonAntique', fontFamily: 'CaslonAntique',
fontSize: 18, fontSize: 18,
fill: '#FFFFFF', fill: '#FFFFFF',
@@ -40,33 +42,10 @@ export class PixiTMR {
PixiTMR.textures[name] = img; PixiTMR.textures[name] = img;
} }
animate(animation = pixiApp=>{}) animate(animation = pixiApp => { }) {
{
this.callbacksOnAnimate.push(() => animation(this.pixiApp)); this.callbacksOnAnimate.push(() => animation(this.pixiApp));
} }
carteTmr(code) {
let img = PixiTMR.getImgFromCode(code)
const carteTmr = new PIXI.Sprite(PIXI.utils.TextureCache[img]);
console.log(code, carteTmr)
// Setup the position of the TMR
carteTmr.x = 0;
carteTmr.y = 0;
carteTmr.width = 720;
carteTmr.height = 860;
// Rotate around the center
carteTmr.anchor.set(0);
carteTmr.eventMode = 'dynamic'; // PIXI 7 : Not sure ..
// This one is deprecated ; carteTmr.interactive = true;
carteTmr.buttonMode = true;
carteTmr.tmrObject = this;
if (!this.tmrObject.viewOnly) {
carteTmr.on('pointerdown', event => this.onClickBackground(event));
}
this.pixiApp.stage.addChild(carteTmr);
return carteTmr;
}
sprite(code, options = {}) { sprite(code, options = {}) {
let img = PixiTMR.getImgFromCode(code) let img = PixiTMR.getImgFromCode(code)
const texture = PIXI.utils.TextureCache[img]; const texture = PIXI.utils.TextureCache[img];
@@ -98,27 +77,37 @@ export class PixiTMR {
return sprite; return sprite;
} }
addTooltip(sprite, text) { addTooltip(sprite, computeTooltip) {
if (text) { sprite.tooltip = new PIXI.Text('', tooltipStyle);
sprite.tooltip = new PIXI.Text(text, tooltipStyle);
sprite.tooltip.zIndex = tmrTokenZIndex.tooltip; sprite.tooltip.zIndex = tmrTokenZIndex.tooltip;
sprite.isOver = false; sprite.isOver = false;
// Deprecated : sprite.interactive = true; sprite.eventMode = 'static';
sprite.eventMode = 'dynamic'; // PIXI 7 To be checked sprite
sprite.on('pointerdown', event => this.onClickBackground(event)) .on('pointermove', event => this.onPointerMove(event, sprite, computeTooltip))
.on('pointerover', () => this.onShowTooltip(sprite)) .on('pointerdown', event => this.onClickBackground(event))
.on('pointerout', () => this.onHideTooltip(sprite)); .on('pointerover', event => this.onShowTooltip(event, sprite))
.on('pointerout', event => this.onHideTooltip(event, sprite));
} }
}
onClickBackground(event) { onClickBackground(event) {
if (!this.viewOnly) {
this.tmrObject.onClickTMR(event) this.tmrObject.onClickTMR(event)
} }
}
onShowTooltip(sprite) { onPointerMove(event, sprite, computeTooltip) {
if (sprite.isOver && sprite.tooltip) {
var { x, y } = TMRUtility.computeEventPosition(event);
const oddq = TMRUtility.computeOddq(x, y);
sprite.tooltip.x = x + (oddq.col > 8 ? - 3 * tmrConstants.full : tmrConstants.half)
sprite.tooltip.y = y + (oddq.row > 10 ? - tmrConstants.half : tmrConstants.half)
sprite.tooltip.text = computeTooltip(event, sprite);
}
}
onShowTooltip(event, sprite) {
if (sprite.tooltip) { if (sprite.tooltip) {
if (!sprite.isOver) { if (!sprite.isOver) {
sprite.tooltip.x = sprite.x; sprite.tooltip.x = sprite.x;
sprite.tooltip.y = sprite.y; sprite.tooltip.y = sprite.y;
@@ -128,7 +117,7 @@ export class PixiTMR {
} }
} }
onHideTooltip(sprite) { onHideTooltip(event, sprite) {
if (sprite.tooltip) { if (sprite.tooltip) {
if (sprite.isOver) { if (sprite.isOver) {
this.pixiApp.stage.removeChild(sprite.tooltip); this.pixiApp.stage.removeChild(sprite.tooltip);

View File

@@ -49,12 +49,13 @@ export class PresentCites extends Draconique {
const presents = await game.system.rdd.rencontresTMR.getPresentsCite() const presents = await game.system.rdd.rencontresTMR.getPresentsCite()
const buttons = {}; const buttons = {};
presents.forEach(r => buttons['present'+r.id] = { icon: '<i class="fas fa-check"></i>', label: r.name, callback: async () => onChoixPresent(r) }); presents.forEach(r => buttons['present'+r.id] = { icon: '<i class="fas fa-check"></i>', label: r.name, callback: async () => onChoixPresent(r) });
let d = new Dialog({ let dialog = new Dialog({
title: "Présent des cités", title: "Présent des cités",
content: `La ${this.tmrLabel(casetmr)} vous offre un présent, faites votre choix`, content: `La ${this.tmrLabel(casetmr)} vous offre un présent, faites votre choix`,
buttons: buttons buttons: buttons
}); });
d.render(true); dialog.render(true);
return dialog
} }
async ouvrirLePresent(actor, casetmr) { async ouvrirLePresent(actor, casetmr) {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 313 KiB

BIN
styles/img/ui/tmr.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 637 KiB

View File

@@ -171,6 +171,9 @@ i:is(.fas, .far) {
width: fit-content; width: fit-content;
} }
.tmr-dialog table {
border: none;
}
.system-foundryvtt-reve-de-dragon .sheet-header div.tmr-buttons { .system-foundryvtt-reve-de-dragon .sheet-header div.tmr-buttons {
padding: 0; padding: 0;
margin: 0; margin: 0;

View File

@@ -1,8 +1,8 @@
{ {
"id": "foundryvtt-reve-de-dragon", "id": "foundryvtt-reve-de-dragon",
"title": "Rêve de Dragon", "title": "Rêve de Dragon",
"version": "11.0.22", "version": "11.0.27",
"download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-11.0.22.zip", "download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-11.0.27.zip",
"manifest": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/v11/system.json", "manifest": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/v11/system.json",
"changelog": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/branch/v11/changelog.md", "changelog": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/branch/v11/changelog.md",
"compatibility": { "compatibility": {

View File

@@ -1,8 +1,7 @@
<form class="tmr-dialog"> <form class="tmr-dialog">
<h2 class="comptmrdialog" id="tmrDialogTitle"></h2> <h2 class="comptmrdialog" id="tmrDialogTitle" style="visibility: hidden;"></h2>
<table>
<table id="tmrsheet"> <tr class="tmr-row">
<tr id="tmrrow1">
<td> <td>
{{#if (eq mode "visu")}} {{#if (eq mode "visu")}}
<div class="flex-group-center"> <div class="flex-group-center">
@@ -54,6 +53,5 @@
</td> </td>
</tr> </tr>
</table> </table>
</form> </form>

View File

@@ -16,6 +16,7 @@
</div> </div>
{{/if}} {{/if}}
<div class="horloge-digitale"> <div class="horloge-digitale">
<span> <span>
<a class="toggle-horloge-analogique"> <a class="toggle-horloge-analogique">
{{#if horlogeAnalogique}} {{#if horlogeAnalogique}}
@@ -33,6 +34,15 @@
{{#if isGM}} {{#if isGM}}
<span class="calendar-minute-texte">{{minute}} minutes</span> <span class="calendar-minute-texte">{{minute}} minutes</span>
{{/if}} {{/if}}
{{#if isGM}}
<span class="toggle-auto-darkness">
{{#if autoDarkness}}
<i class="fa-solid fa-lightbulb"></i>
{{else}}
<i class="fa-regular fa-lightbulb"></i>
{{/if}}
</span>
{{/if}}
</div> </div>
<div class="horloge-analogique {{#unless horlogeAnalogique}}horloge-analogique-hidden{{/unless}}"> <div class="horloge-analogique {{#unless horlogeAnalogique}}horloge-analogique-hidden{{/unless}}">
{{> 'systems/foundryvtt-reve-de-dragon/templates/time/horloge.hbs' }} {{> 'systems/foundryvtt-reve-de-dragon/templates/time/horloge.hbs' }}