diff --git a/module/actor-entite-sheet.js b/module/actor-entite-sheet.js index 8508c7ee..aa836cbf 100644 --- a/module/actor-entite-sheet.js +++ b/module/actor-entite-sheet.js @@ -108,11 +108,11 @@ export class RdDActorEntiteSheet extends ActorSheet { this.actor.rollCompetence( compName ); }); - html.find('#endurance-plus').click((event) => { + html.find('.endurance-plus').click((event) => { this.actor.santeIncDec("endurance", 1); this.render(true); }); - html.find('#endurance-moins').click((event) => { + html.find('.endurance-moins').click((event) => { this.actor.santeIncDec("endurance", -1); this.render(true); }); diff --git a/module/actor-sheet.js b/module/actor-sheet.js index 3306bb30..53e04120 100644 --- a/module/actor-sheet.js +++ b/module/actor-sheet.js @@ -78,7 +78,9 @@ export class RdDActorSheet extends ActorSheet { formData.calc.surEncombrementMessage = (formData.data.compteurs.surenc.value < 0) ? "Sur-Encombrement!" : ""; formData.competences.forEach(item => { - item.visible = !this.options.showCompNiveauBase || !RdDItemCompetence.isNiveauBase(item); + item.visible = this.options.cherchercompetence + ? RdDItemCompetence.nomContientTexte(item, this.options.cherchercompetence) + : ( !this.options.showCompNiveauBase || !RdDItemCompetence.isNiveauBase(item) ); RdDItemCompetence.levelUp(item, formData.data.compteurs.experience.value); }); @@ -421,6 +423,10 @@ export class RdDActorSheet extends ActorSheet { this.options.editCaracComp = !this.options.editCaracComp; this.render(true); }); + html.find('.cherchercompetence').change(async event => { + this.options.cherchercompetence = event.currentTarget.value; + this.render(true); + }); html.find('.vue-detaillee').click(async event => { console.log("CONTROLS", this.options.vueDetaillee) this.options.vueDetaillee = !this.options.vueDetaillee; @@ -468,10 +474,10 @@ export class RdDActorSheet extends ActorSheet { this.actor.jetEthylisme(); }); - html.find('#jet-vie').click(async event => { + html.find('.jet-vie').click(async event => { this.actor.jetVie(); }); - html.find('#jet-endurance').click(async event => { + html.find('.jet-endurance').click(async event => { this.actor.jetEndurance(); }); @@ -484,28 +490,28 @@ export class RdDActorSheet extends ActorSheet { this.actor.monnaieIncDec(li.data("item-id"), -1); }); - html.find('#vie-plus').click(async event => { + html.find('.vie-plus').click(async event => { this.actor.santeIncDec("vie", 1); }); - html.find('#vie-moins').click(async event => { + html.find('.vie-moins').click(async event => { this.actor.santeIncDec("vie", -1); }); - html.find('#endurance-plus').click(async event => { + html.find('.endurance-plus').click(async event => { this.actor.santeIncDec("endurance", 1); }); - html.find('#endurance-moins').click(async event => { + html.find('.endurance-moins').click(async event => { this.actor.santeIncDec("endurance", -1); }); - html.find('#ptreve-actuel-plus').click(async event => { + html.find('.ptreve-actuel-plus').click(async event => { this.actor.reveActuelIncDec(1); }); - html.find('#ptreve-actuel-moins').click(async event => { + html.find('.ptreve-actuel-moins').click(async event => { this.actor.reveActuelIncDec(-1); }); - html.find('#fatigue-plus').click(async event => { + html.find('.fatigue-plus').click(async event => { this.actor.santeIncDec("fatigue", 1); }); - html.find('#fatigue-moins').click(async event => { + html.find('.fatigue-moins').click(async event => { this.actor.santeIncDec("fatigue", -1); }); } diff --git a/module/actor.js b/module/actor.js index 3ca22631..ae849614 100644 --- a/module/actor.js +++ b/module/actor.js @@ -63,7 +63,7 @@ export class RdDActor extends Actor { } static remoteActorCall(data) { - if (Misc.isElectedUser()) { + if (Misc.isUniqueConnectedGM()) { RdDActor.onRemoteActorCall(data); } else { @@ -72,7 +72,7 @@ export class RdDActor extends Actor { } static onRemoteActorCall(data) { - if (Misc.isElectedUser()) { // Seul le joueur choisi effectue l'appel + if (Misc.isUniqueConnectedGM()) { // Seul le joueur choisi effectue l'appel const actor = game.actors.get(data?.actorId); if (!actor) { console.info("RdDActor.onRemoteActorCall: Pas d'Actor disponible ", data); @@ -3685,7 +3685,7 @@ export class RdDActor extends Actor { ui.notifications.info("Inutile de se vendre à soi-même"); return; } - if (!Misc.isElectedUser()) { + if (!Misc.isUniqueConnectedGM()) { RdDActor.remoteActorCall({actorId: achat.vendeurId ?? achat.acheteurId, method: 'achatVente', args: [achat]}); return; } @@ -4172,7 +4172,7 @@ export class RdDActor extends Actor { /* -------------------------------------------- */ async onCreateOwnedDraconique(item, options, id) { - if (Misc.isElectedUser()) { + if (Misc.isUniqueConnectedGM()) { let draconique = Draconique.all().find(it => it.match(item)); if (draconique) { draconique.onActorCreateOwned(this, item) @@ -4183,7 +4183,7 @@ export class RdDActor extends Actor { /* -------------------------------------------- */ async onDeleteOwnedDraconique(item, options, id) { - if (Misc.isElectedUser()) { + if (Misc.isUniqueConnectedGM()) { let draconique = Draconique.all().find(it => it.match(item)); if (draconique) { draconique.onActorDeleteOwned(this, item) @@ -4193,7 +4193,7 @@ export class RdDActor extends Actor { /* -------------------------------------------- */ async onDeleteOwnedCaseTmr(item, options, id) { - if (Misc.isElectedUser()) { + if (Misc.isUniqueConnectedGM()) { let draconique = Draconique.all().find(it => it.isCase(item)); if (draconique) { draconique.onActorDeleteCaseTmr(this, Misc.data(item)) diff --git a/module/chat-utility.js b/module/chat-utility.js index dd80bb55..224b2d2b 100644 --- a/module/chat-utility.js +++ b/module/chat-utility.js @@ -41,7 +41,7 @@ export class ChatUtility { /* -------------------------------------------- */ static onRemoveMessages(data) { - if (Misc.isElectedUser()) { + if (Misc.isUniqueConnectedGM()) { if (data.part) { const toDelete = game.messages.filter(it => it.data.content.includes(data.part)); toDelete.forEach(it => it.delete()); @@ -53,7 +53,7 @@ export class ChatUtility { } static onRemoveMessages(data) { - if (Misc.isElectedUser()) { + if (Misc.isUniqueConnectedGM()) { if (data.part) { const toDelete = game.messages.filter(it => it.data.content.includes(data.part)); toDelete.forEach(it => it.delete()); @@ -66,7 +66,7 @@ export class ChatUtility { /* -------------------------------------------- */ static removeMessages(data) { - if (Misc.isElectedUser()){ + if (Misc.isUniqueConnectedGM()){ ChatUtility.onRemoveMessages(data); } else { diff --git a/module/dialog-stress.js b/module/dialog-stress.js index 210b9918..cc136977 100644 --- a/module/dialog-stress.js +++ b/module/dialog-stress.js @@ -46,9 +46,9 @@ export class DialogStress extends Dialog { validerStress() { - this.dialogData.motif = $("[name='motif']").val(); - this.dialogData.stress = $("[name='stress']").val(); - this.dialogData.immediat = $("[name='immediat']").prop("checked");; + this.dialogData.motif = $("form.rdddialogstress input[name='motif']").val(); + this.dialogData.stress = $("form.rdddialogstress input[name='stress']").val(); + this.dialogData.immediat = $("form.rdddialogstress input[name='immediat']").prop("checked");; } /* -------------------------------------------- */ diff --git a/module/item-competence.js b/module/item-competence.js index 8abae8cf..268e4116 100644 --- a/module/item-competence.js +++ b/module/item-competence.js @@ -201,6 +201,10 @@ export class RdDItemCompetence extends Item { return Number(itemData.data.niveau) != RdDItemCompetence.getNiveauBase(itemData.data.categorie); } + static nomContientTexte(itemData, texte) { + return Grammar.toLowerCaseNoAccent(itemData.name).includes(Grammar.toLowerCaseNoAccent(texte)) + } + /* -------------------------------------------- */ static isNiveauBase(itemData) { return Number(itemData.data.niveau) == RdDItemCompetence.getNiveauBase(itemData.data.categorie); diff --git a/module/misc.js b/module/misc.js index f6e0c7f1..4c553757 100644 --- a/module/misc.js +++ b/module/misc.js @@ -101,6 +101,11 @@ export class Misc { return [...new Set(array)]; } + static join(params, separator = '') { + return params.reduce((a, b) => a + separator + b); + } + + static data(it) { if (it instanceof Actor || it instanceof Item || it instanceof Combatant) { return it.data; @@ -126,10 +131,22 @@ export class Misc { if (ownerId && game.user.id == ownerId) { return ownerId; } - return (game.user.isGM ? game.user.id : game.users.entities.find(u => u.isGM && u.active)?.id) ?? game.user.id; + return Misc.firstConnectedGM()?.id ?? game.user.id; } - static isElectedUser() { - return game.user.id == Misc.connectedGMOrUser(); + + static getActiveUser(id) { + return game.users.entities.find(u => u.id == id && u.active); + } + + static firstConnectedGM() { + return game.users.entities.sort(Misc.ascending(u => u.id)).find(u => u.isGM && u.active); + } + + /** + * @returns true pour un seul utilisateur: le premier GM connecté par ordre d'id + */ + static isUniqueConnectedGM() { + return game.user.id == Misc.firstConnectedGM()?.id; } /* -------------------------------------------- */ @@ -161,7 +178,7 @@ export class Misc { let single = subset.find(it => Grammar.toLowerCaseNoAccent(options.mapper(it)) == Grammar.toLowerCaseNoAccent(value)); if (!single) { single = subset[0]; - const choices = subset.map(it => options.mapper(it)).reduce((a, b) => `${a}
${b}`); + const choices = Misc.join(subset.map(it => options.mapper(it)), '
'); options.info(`Plusieurs choix de ${options.description}s possibles:
${choices}
Le premier sera choisi: ${mapToValue(single)}`); } return single; diff --git a/module/rdd-astrologie-joueur.js b/module/rdd-astrologie-joueur.js index dd5ae006..bf0c3692 100644 --- a/module/rdd-astrologie-joueur.js +++ b/module/rdd-astrologie-joueur.js @@ -68,9 +68,10 @@ export class RdDAstrologieJoueur extends Dialog { etat: this.dataNombreAstral.etat, astrologie: this.dataNombreAstral.astrologie, conditions: $("#diffConditions").val(), - date: $("#joursAstrologie").val() + date: $("#joursAstrologie").val(), + userId: game.user.id } - if (game.user.isGM) { + if (Misc.isUniqueConnectedGM()) { game.system.rdd.calendrier.requestNombreAstral(data); } else { game.socket.emit("system.foundryvtt-reve-de-dragon", { @@ -83,7 +84,6 @@ export class RdDAstrologieJoueur extends Dialog { /* -------------------------------------------- */ quitDialog() { - } /* -------------------------------------------- */ diff --git a/module/rdd-calendrier.js b/module/rdd-calendrier.js index 4807f485..aa923569 100644 --- a/module/rdd-calendrier.js +++ b/module/rdd-calendrier.js @@ -82,12 +82,9 @@ export class RdDCalendrier extends Application { this.calendrier.annee = this.calendrier.annee ?? Math.floor((this.calendrier.moisRdD ?? 0) / RDD_MOIS_PAR_AN); this.calendrier.moisRdD = (this.calendrier.moisRdD ?? 0) % RDD_MOIS_PAR_AN; - if (game.user.isGM) { // Uniquement si GM + if (Misc.isUniqueConnectedGM()) { // Uniquement si GM game.settings.set(SYSTEM_RDD, "calendrier", this.calendrier); - } - // nombre astral - if (game.user.isGM) { this.listeNombreAstral = this.getListeNombreAstral(); this.rebuildListeNombreAstral(false); // Ensure always up-to-date } @@ -189,7 +186,7 @@ export class RdDCalendrier extends Application { /* -------------------------------------------- */ async rebuildListeNombreAstral(showDice = true) { - if (game.user.isGM) { + if (Misc.isUniqueConnectedGM()) { console.log("rebuildListeNombreAstral", showDice); let jourCourant = this.getCurrentDayIndex(); let newList = []; @@ -320,7 +317,7 @@ export class RdDCalendrier extends Application { /* -------------------------------------------- */ async requestNombreAstral(request) { - if (game.user.isGM) { // Only GM + if (Misc.isUniqueConnectedGM()) { // Only once console.log(request); let jourDiff = this.getLectureAstrologieDifficulte(request.date); let niveau = Number(request.astrologie.data.niveau) + Number(request.conditions) + Number(jourDiff) + Number(request.etat); @@ -343,7 +340,7 @@ export class RdDCalendrier extends Application { game.settings.set(SYSTEM_RDD, "liste-nombre-astral", this.listeNombreAstral); } request.nbAstral = nbAstral; - if (game.user.isGM) { + if (Misc.getActiveUser(request.userId)?.isGM) { RdDUtility.responseNombreAstral(request); } else { game.socket.emit("system.foundryvtt-reve-de-dragon", { diff --git a/module/rdd-combat.js b/module/rdd-combat.js index 4fb9e504..6826fcf6 100644 --- a/module/rdd-combat.js +++ b/module/rdd-combat.js @@ -227,7 +227,7 @@ export class RdDCombatManager extends Combat { /* -------------------------------------------- */ static processPremierRoundInit() { // Check if we have the whole init ! - if (game.user.isGM && game.combat.current.round == 1) { + if (Misc.isUniqueConnectedGM() && game.combat.current.round == 1) { let initMissing = game.combat.data.combatants.find(it => !it.initiative); if (!initMissing) { // Premier round ! for (let combatant of game.combat.data.combatants) { @@ -422,7 +422,7 @@ export class RdDCombat { /* -------------------------------------------- */ static combatNouveauTour(combat) { - if (Misc.isElectedUser()) { + if (Misc.isUniqueSingleUser()) { let turn = combat.turns.find(t => t.token?.id == combat.current.tokenId); if (turn?.actor) { RdDCombat.displayActorCombatStatus(combat, turn.actor); @@ -540,7 +540,7 @@ export class RdDCombat { /* -------------------------------------------- */ static onMsgEncaisser(data) { - if (Misc.isElectedUser()) { + if (Misc.isUniqueSingleUser()) { let attackerRoll = RdDCombat._getAttaque(data.attackerId); // Retrieve the rolldata from the store let attacker = data.attackerId ? game.actors.get(data.attackerId) : null; let defender = canvas.tokens.get(data.defenderTokenId).actor; @@ -555,7 +555,7 @@ export class RdDCombat { /* -------------------------------------------- */ static onMsgDefense(msg) { let defenderToken = canvas.tokens.get(msg.defenderTokenId); - if (defenderToken && Misc.isElectedUser()) { + if (defenderToken && Misc.isUniqueSingleUser()) { const rddCombat = RdDCombat.createForAttackerAndDefender(msg.attackerId, msg.defenderTokenId); if (rddCombat) { const defenderRoll = msg.defenderRoll; @@ -913,7 +913,7 @@ export class RdDCombat { dmg: attackerRoll.dmg, }; - if (!Misc.isElectedUser()) { + if (!Misc.isUniqueSingleUser()) { this._socketSendMessageDefense(paramChatDefense, defenderRoll); } else { @@ -1286,7 +1286,7 @@ export class RdDCombat { this._onEchecTotal(defenderRoll); } - if (Misc.isElectedUser()) { + if (Misc.isUniqueSingleUser()) { attackerRoll.attackerId = this.attackerId; attackerRoll.defenderTokenId = defenderTokenId; diff --git a/module/rdd-commands.js b/module/rdd-commands.js index ef2840b3..5e1a1c6d 100644 --- a/module/rdd-commands.js +++ b/module/rdd-commands.js @@ -2,6 +2,7 @@ import { DialogCreateSigneDraconique } from "./dialog-create-signedraconique.js"; import { DialogStress } from "./dialog-stress.js"; +import { Grammar } from "./grammar.js"; import { RdDItemCompetence } from "./item-competence.js"; import { Misc } from "./misc.js"; import { RdDCarac } from "./rdd-carac.js"; @@ -40,6 +41,11 @@ export class RdDCommands { descr: `Tire une case aléatoire des Terres médianes
/tmra forêt détermine une 'forêt' aléatoire
/tmra détermine une case aléatoire dans toutes les TMR` }); + rddCommands.registerCommand({ + path: ["/tmr"], func: (content, msg, params) => rddCommands.findTMR(msg, params), + descr: `Cherche où se trouve une case des Terres médianes +
/tmr? sordide indique que la cité Sordide est en D13 +
/tmr? foret donne la liste des TMR dont le nom contient "foret" (donc, toutes les forêts)` }); rddCommands.registerCommand({ path: ["/tmrr"], func: (content, msg, params) => rddCommands.getRencontreTMR(params), descr: `Détermine une rencontre dans un type de case @@ -80,7 +86,7 @@ export class RdDCommands {
/payer 10d permet d'envoyer un message pour payer 10 deniers` }); rddCommands.registerCommand({ - path: ["/astro"], func: (content, msg, params) => RdDUtility.afficherHeuresChanceMalchance(RdDCommands.toParamString(params)), + path: ["/astro"], func: (content, msg, params) => RdDUtility.afficherHeuresChanceMalchance(Misc.join(params, ' ')), descr: `Affiche les heures de chance et de malchance selon l'heure de naissance donnée en argument. Exemples pour l'heure de la Lyre:
/astro 7
/astro Lyre @@ -113,10 +119,6 @@ export class RdDCommands { this.commandsTable = {}; } - static toParamString(params) { - return params.length == 1 ? params[0] : params.reduce((a, b) => `${a} ${b}`, ''); - } - /* -------------------------------------------- */ registerCommand(command) { this._addCommand(this.commandsTable, command.path, '', command); @@ -160,7 +162,7 @@ export class RdDCommands { if (rollMode === "blindroll") msg["blind"] = true; msg["type"] = 0; - let command = commandLine[0]; + let command = commandLine[0].toLowerCase(); let params = commandLine.slice(1); return this.process(command, params, content, msg); @@ -251,7 +253,7 @@ export class RdDCommands { RdDRollResolutionTable.open(); } else { - let flatParams = params.reduce((a, b) => `${a} ${b}`); + let flatParams = Misc.join(params, ' '); const numericParams = flatParams.match(rddRollNumeric); if (numericParams) { const carac = Misc.toInt(numericParams[1]); @@ -272,7 +274,7 @@ export class RdDCommands { diff = 0; } const caracName = params[0]; - const compName = length > 1 ? params.slice(1, length).reduce((a, b) => `${a} ${b}`) : undefined; + const compName = length > 1 ? Misc.join(params.slice(1, length), ' ') : undefined; for (let actor of actors) { await actor.rollCaracCompetence(caracName, compName, diff); } @@ -314,6 +316,14 @@ export class RdDCommands { } } + async findTMR(msg, params) { + const search = Misc.join(params, ' '); + const found = TMRUtility.findTMR(search); + if (found?.length > 0) { + return RdDCommands._chatAnswer(msg, `Les TMRs correspondant à '${search}' sont:` + Misc.join(found.map(it => `
${it.coord}: ${it.label}`))); + } + return RdDCommands._chatAnswer(msg, 'Aucune TMR correspondant à ' + search); + } /* -------------------------------------------- */ getCoutXpComp(msg, params) { @@ -359,7 +369,7 @@ export class RdDCommands { ui.notifications.warn("Seul le MJ est autorisé à utiliser la commande /stress"); return false; } - if (params.length == 0) { + if (params.length < 3) { DialogStress.distribuerStress(); } else { @@ -369,8 +379,8 @@ export class RdDCommands { return; } - let motif = params[1]; - let name = params[2]; + let motif = params.slice(1, params.length - 2); + let name = params[params.length - 1]; if (name == undefined) { for (let actor of game.actors) { actor.distribuerStress('stress', stress, motif); diff --git a/module/rdd-main.js b/module/rdd-main.js index 63680276..503854fe 100644 --- a/module/rdd-main.js +++ b/module/rdd-main.js @@ -34,6 +34,7 @@ import { RdDItem } from "./item.js"; import { RdDDice } from "./rdd-dice.js"; import { RdDPossession } from "./rdd-possession.js"; import { RdDSigneDraconiqueItemSheet } from "./item-signedraconique-sheet.js"; +import { Misc } from "./misc.js"; /* -------------------------------------------- */ /* Foundry VTT Initialization */ @@ -254,7 +255,7 @@ Hooks.once("ready", async function () { user: game.user.id }); } - if (game.user.isGM) { + if (Misc.isUniqueConnectedGM()) { messageDeBienvenue(); } }); @@ -299,7 +300,7 @@ Hooks.once('diceSoNiceReady', (dice3d) => RdDDice.diceSoNiceReady(dice3d)); Hooks.on("chatMessage", (html, content, msg) => { if (content[0] == '/') { let regExp = /(\S+)/g; - let commands = content.toLowerCase().match(regExp); + let commands = content.match(regExp); if (game.system.rdd.commands.processChatCommand(commands, content, msg)) { return false; } diff --git a/module/tmr-utility.js b/module/tmr-utility.js index 32d4015f..a54de95e 100644 --- a/module/tmr-utility.js +++ b/module/tmr-utility.js @@ -347,7 +347,7 @@ export class TMRUtility { return Grammar.articleDetermine(tmr.type) + ' ' + tmr.label; } - static typeTmrName(type){ + static typeTmrName(type) { return Misc.upperFirst(TMRType[Grammar.toLowerCaseNoAccent(type)].name); } static listSelectedTMR(typesTMR) { @@ -424,6 +424,11 @@ export class TMRUtility { return Object.values(TMRMapping).filter(filter); } + static findTMR(search) { + const labelSearch = Grammar.toLowerCaseNoAccent(search) + return TMRUtility.filterTMR(it => Grammar.toLowerCaseNoAccent(it.label).match(labelSearch) || it.coord == search); + } + static filterTMRCoord(filter) { return TMRUtility.filterTMR(filter).map(it => it.coord); } diff --git a/module/tmr/pixi-tmr.js b/module/tmr/pixi-tmr.js index 17398396..d28616bd 100644 --- a/module/tmr/pixi-tmr.js +++ b/module/tmr/pixi-tmr.js @@ -55,12 +55,6 @@ export class PixiTMR { carteTmr.interactive = true; carteTmr.buttonMode = true; carteTmr.tmrObject = this; - // atténue les couleurs des TMRs - const tmrColorFilter = new PIXI.filters.ColorMatrixFilter(); - tmrColorFilter.contrast(1); - tmrColorFilter.brightness(0.2); - tmrColorFilter.saturate(-0.5); - carteTmr.filters = [tmrColorFilter]; if (!this.tmrObject.viewOnly) { carteTmr.on('pointerdown', event => this.onClickBackground(event)); } diff --git a/styles/img/ui/tmp_main_r1.webp b/styles/img/ui/tmp_main_r1.webp index ad58bbb1..a7bb19c4 100644 Binary files a/styles/img/ui/tmp_main_r1.webp and b/styles/img/ui/tmp_main_r1.webp differ diff --git a/styles/simple.css b/styles/simple.css index c9e26778..e3a37cbe 100644 --- a/styles/simple.css +++ b/styles/simple.css @@ -644,7 +644,7 @@ section.sheet-body:after { max-width: 90%; } -#vie-plus, #vie-moins, #endurance-plus, #endurance-moins, #fatigue-plus, #fatigue-moins, #ptreve-actuel-plus, #ptreve-actuel-moins, .monnaie-plus, .monnaie-moins { +.plus-moins { display: inline-block; width: 1.25rem; background: rgba(30, 25, 20, 1); diff --git a/templates/actor-sheet-categorie-competences-partial.html b/templates/actor-sheet-categorie-competences-partial.html index 8a20a5e5..75ea7bd4 100644 --- a/templates/actor-sheet-categorie-competences-partial.html +++ b/templates/actor-sheet-categorie-competences-partial.html @@ -2,6 +2,25 @@ {{categorie}}