diff --git a/module/actor-sheet.js b/module/actor-sheet.js index 9080d850..9281bb0f 100644 --- a/module/actor-sheet.js +++ b/module/actor-sheet.js @@ -11,7 +11,6 @@ import { RdDBonus } from "./rdd-bonus.js"; import { Misc } from "./misc.js"; import { RdDCombatManager } from "./rdd-combat.js"; import { RdDCarac } from "./rdd-carac.js"; -import { RdDItem } from "./item.js"; import { DialogSplitItem } from "./dialog-split-item.js"; import { ReglesOptionelles } from "./regles-optionelles.js"; import { DialogRepos } from "./dialog-repos.js"; @@ -93,7 +92,7 @@ export class RdDActorSheet extends ActorSheet { formData.combat = duplicate(formData.armes ?? []); RdDItemArme.computeNiveauArmes(formData.combat, formData.competences); RdDItemArme.ajoutCorpsACorps(formData.combat, formData.competences, formData.data.carac); - formData.esquive = RdDItemCompetence.getEsquive(formData.competences); + formData.esquives = this.actor.getCompetences("Esquive").map(i => foundry.utils.deepClone(i.data)); formData.combat = RdDCombatManager.finalizeArmeList(formData.combat, formData.competences, formData.data.carac); this.armesList = formData.combat; @@ -345,24 +344,16 @@ export class RdDActorSheet extends ActorSheet { // Roll Weapon1 html.find('.arme-label a').click(async event => { - let armeName = event.currentTarget.text; - let compName = event.currentTarget.attributes['data-competence-name'].value; - let arme = this.actor.data.items.find(it => - it.name == armeName && - RdDItemArme.isArme(it) && - ((compName || it.data.data.competence) == it.data.data.competence) - ); - if (!arme) { - arme = { name: armeName, data: { competence: compName } }; - } + const li = $(event.currentTarget).parents(".item"); + let arme = this._getArmeCombat(li); this.actor.rollArme( duplicate(arme) ); }); // Initiative pour l'arme html.find('.arme-initiative a').click(async event => { let combatant = game.combat.data.combatants.find(c => c.actor.data._id == this.actor.data._id); if (combatant) { - let armeName = event.currentTarget.attributes['data-arme-name'].value; - let arme = this.armesList.find(a => a.name == armeName); + const li = $(event.currentTarget).parents(".item"); + let arme = this._getArmeCombat(li); RdDCombatManager.rollInitiativeCompetence(combatant._id, arme); } else { ui.notifications.info("Impossible de lancer l'initiative sans être dans un combat."); @@ -544,6 +535,16 @@ export class RdDActorSheet extends ActorSheet { } + _getArmeCombat(li) { + let armeName = li.data("arme-name"); + let compName = li.data('competence-name'); + const arme = this.armesList.find(a => a.name == armeName && a.data.competence == compName); + if (!arme) { + return { name: armeName, data: { competence: compName } }; + } + return arme; + } + /* -------------------------------------------- */ /** @override */ setPosition(options = {}) { diff --git a/module/actor.js b/module/actor.js index 7ec70482..faf7aaf4 100644 --- a/module/actor.js +++ b/module/actor.js @@ -313,13 +313,19 @@ export class RdDActor extends Actor { return Misc.templateData(this).compteurs.surenc?.value ?? 0; } /* -------------------------------------------- */ - getCompetence(name) { - return RdDItemCompetence.findCompetence(this.data.items, name); + getCompetence(idOrName, options={}) { + return RdDItemCompetence.findCompetence(this.data.items, idOrName, options); } + + getCompetences(name) { + return RdDItemCompetence.findCompetences(this.data.items, name); + } + /* -------------------------------------------- */ getObjet(id) { return id ? this.data.items.find(it => it.id == id) : undefined; } + listItemsData(type) { return this.filterItemsData(it => it.type == type); } @@ -329,16 +335,12 @@ export class RdDActor extends Actor { filterItems(filter) { return this.data.items.filter(it => filter(Misc.data(it))); } - getItemOfType(id, type) { - if (id && type) { - let itemById = this.data.items.find(it => it.id == id); - const itemData = Misc.data(itemById); - if (itemData.type == type) { - return itemById; - } - } - return undefined; + + getItemOfType(idOrName, type) { + return this.data.items.find(it => it.id == idOrName && it.type == type) + ?? Misc.findFirstLike(idOrName, this.data.items,{filter: it => it.type == type, description: type}); } + getMonnaie(id) { return this.getItemOfType(id, 'monnaie'); } @@ -3077,7 +3079,7 @@ export class RdDActor extends Actor { case 'chance-actuelle': case 'chance actuelle': return carac.chance; } - let entry = Misc.findFirstLike(name, Object.entries(carac), it => it[1].label, 'caractéristiques'); + let entry = Misc.findFirstLike(name, Object.entries(carac), {mapper:it => it[1].label, description: 'caractéristique'}); return entry.length>0 ? carac[entry[0]] : undefined; } diff --git a/module/item-arme.js b/module/item-arme.js index f18bb712..b1f1aafa 100644 --- a/module/item-arme.js +++ b/module/item-arme.js @@ -171,12 +171,13 @@ export class RdDItemArme extends Item { let corpsACorps = competences.find(it => it.name == 'Corps à corps') ?? { data: { niveau: -6 } }; let init = RdDCombatManager.calculInitiative(corpsACorps.data.niveau, carac['melee'].value); armes.push(RdDItemArme.mainsNues({ niveau: corpsACorps.data.niveau, initiative: init })); - armes.push(RdDItemArme.empoignade({ niveau: corpsACorps.data.niveau, initiative: init })); + //armes.push(RdDItemArme.empoignade({ niveau: corpsACorps.data.niveau, initiative: init })); } static corpsACorps(actorData) { const corpsACorps = { name: 'Corps à corps', + img: 'systems/foundryvtt-reve-de-dragon/icons/competence_corps_a_corps.webp', data: { equipe: true, rapide: true, diff --git a/module/item-competence.js b/module/item-competence.js index c2355ab1..4a7c246c 100644 --- a/module/item-competence.js +++ b/module/item-competence.js @@ -79,18 +79,12 @@ export class RdDItemCompetence extends Item { return Misc.data(competence)?.data.categorie; } static isDraconic(competence) { - return Misc.data(competence).data.categorie == 'draconic'; + return Misc.data(competence)?.data.categorie == 'draconic'; } /* -------------------------------------------- */ static getVoieDraconic(competences, voie) { - voie = Grammar.toLowerCaseNoAccent(voie); - return competences.find(it => RdDItemCompetence.isDraconic(it) && Grammar.toLowerCaseNoAccent(Misc.data(it).name).includes(voie)); - } - - /* -------------------------------------------- */ - static getEsquive(competences) { - return { name: 'Esquive', niveau: RdDItemCompetence.findCompetence(competences, 'Esquive')?.data.niveau ?? -6 }; + return RdDItemCompetence.findCompetence(competences.filter(it => RdDItemCompetence.isDraconic(it) ), voie); } /* -------------------------------------------- */ @@ -208,8 +202,22 @@ export class RdDItemCompetence extends Item { } /* -------------------------------------------- */ - static findCompetence(list, name) { - return Misc.findFirstLike(name, list, it => it.name, 'compétences'); + static findCompetence(list, idOrName, options = {}) { + options = mergeObject(options, { + filter: it => RdDItemCompetence.isCompetence(it), + description: 'compétence', + }); + return list.find(it => it.id == idOrName && RdDItemCompetence.isCompetence(it)) + ?? Misc.findFirstLike(idOrName, list, options); + } + + /* -------------------------------------------- */ + static findCompetences(list, name) { + return Misc.findAllLike(name, list, { filter: it => RdDItemCompetence.isCompetence(it), description: 'compétence' }); + } + + static isCompetence(item) { + return item.type == 'competence' || item.type == 'competencecreature'; } /* -------------------------------------------- */ diff --git a/module/misc.js b/module/misc.js index 2f4b106d..f6e0c7f1 100644 --- a/module/misc.js +++ b/module/misc.js @@ -134,33 +134,57 @@ export class Misc { /* -------------------------------------------- */ static findPlayer(name) { - return Misc.findFirstLike(name, game.users, it=>it.name,'joueurs'); + return Misc.findFirstLike(name, game.users, { description: 'joueur' }); } /* -------------------------------------------- */ - static findActor(name, actors = game.actors, description= 'acteurs') { - return Misc.findFirstLike(name, actors, it=>it.name, description); + static findActor(name, actors = game.actors) { + return Misc.findFirstLike(name, actors, { description: 'acteur' }); } /* -------------------------------------------- */ - static findFirstLike(value, elements, mapper = it=>it.name, description = 'valeurs') { - if (!value) { - return undefined; - } - value = Grammar.toLowerCaseNoAccent(value); - const subset = elements.filter(it => Grammar.toLowerCaseNoAccent(mapper(it)).includes(value)); + static findFirstLike(value, elements, options = {}) { + options = mergeObject({ + mapper: it => it.name, + preFilter: it => true, + description: 'valeur', + onMessage: m => ui.notifications.info(m) + }, options); + + const subset = this.findAllLike(value, elements, options); if (subset.length == 0) { - ui.notifications.info(`Pas de ${description} correspondant à ${value}`); - return undefined; + return undefined } - let single = subset.find(it => Grammar.toLowerCaseNoAccent(mapper(it)) == value); + if (subset.length == 1) { + return subset[0] + } + let single = subset.find(it => Grammar.toLowerCaseNoAccent(options.mapper(it)) == Grammar.toLowerCaseNoAccent(value)); if (!single) { single = subset[0]; - if (subset.length > 1) { - const choices = subset.map(it => mapper(it)).reduce((a, b) => `${a}
${b}`); - ui.notifications.info(`Plusieurs choix de ${description} possibles:
${choices}
Le premier sera choisi: ${mapper(single)}`); - } + const choices = subset.map(it => options.mapper(it)).reduce((a, b) => `${a}
${b}`); + options.info(`Plusieurs choix de ${options.description}s possibles:
${choices}
Le premier sera choisi: ${mapToValue(single)}`); } return single; } + + static findAllLike(value, elements, options = {}) { + options = mergeObject({ + mapper: it => it.name, + preFilter: it => true, + description: 'valeur', + onMessage: m => ui.notifications.info(m) + }, options); + + if (!value) { + options.onMessage(`Pas de ${options.description} correspondant à une valeur vide`); + return []; + } + value = Grammar.toLowerCaseNoAccent(value); + const subset = elements.filter(options.preFilter) + .filter(it => Grammar.toLowerCaseNoAccent(options.mapper(it)).includes(value)); + if (subset.length == 0) { + options.onMessage(`Pas de ${options.description} correspondant à ${value}`); + } + return subset; + } } \ No newline at end of file diff --git a/module/rdd-combat.js b/module/rdd-combat.js index facb5b39..4fb9e504 100644 --- a/module/rdd-combat.js +++ b/module/rdd-combat.js @@ -151,11 +151,12 @@ export class RdDCombatManager extends Combat { // Gestion des armes 1/2 mains let armesEquipe = []; for (const arme of armes) { - let armeData = Misc.data(arme); + let armeData = duplicate(Misc.data(arme)); if (armeData.data.equipe) { let compData = competences.map(c => Misc.data(c)).find(c => c.name == armeData.data.competence); armesEquipe.push(armeData); + armeData.data.dommagesReels = Number(armeData.data.dommages); armeData.data.niveau = compData.data.niveau; armeData.data.initiative = RdDCombatManager.calculInitiative(compData.data.niveau, carac[compData.data.defaut_carac].value); // Dupliquer les armes pouvant être à 1 main et 2 mains en patchant la compétence @@ -165,14 +166,25 @@ export class RdDCombatManager extends Combat { armeData.data.mainInfo = "(2m)"; } else if (armeData.data.unemain && armeData.data.deuxmains) { armeData.data.mainInfo = "(1m)"; - let arme2main = duplicate(armeData); + + const comp2m = armeData.data.competence.replace(" 1 main", " 2 mains"); // Replace ! + const comp = Misc.data(competences.find(c => c.name == comp2m)); + + const arme2main = duplicate(armeData); arme2main.data.mainInfo = "(2m)"; - arme2main.data.dommages = arme2main.data.dommages.split("/")[1]; // Existence temporaire uniquement dans la liste des armes, donc OK - arme2main.data.competence = arme2main.data.competence.replace(" 1 main", " 2 mains"); // Replace ! - let comp = Misc.data(competences.find(c => c.name == arme2main.data.competence)); arme2main.data.niveau = comp.data.niveau; + arme2main.data.competence = comp2m; arme2main.data.initiative = RdDCombatManager.calculInitiative(arme2main.data.niveau, carac[comp.data.defaut_carac].value); armesEquipe.push(arme2main); + const containsSlash = armeData.data.dommages.includes("/"); + if (containsSlash) { + const tableauDegats = armeData.data.dommages.split("/"); + armeData.data.dommagesReels = Number(tableauDegats[0]); + arme2main.data.dommagesReels = Number(tableauDegats[1]); + } + else{ + ui.notifications.info("Les dommages de l'arme à 1/2 mains " + armeData.name + " ne sont pas corrects (ie sous la forme X/Y)"); + } } } } @@ -194,8 +206,8 @@ export class RdDCombatManager extends Combat { } else { // Recupération des items 'arme' let armes = items.filter(it => RdDItemArme.isArmeUtilisable(it)) - .concat(RdDItemArme.mainsNues()) - .concat(RdDItemArme.empoignade()); + //.concat(RdDItemArme.empoignade()) + .concat(RdDItemArme.mainsNues()); let competences = items.filter(it => it.type == 'competence'); actions = actions.concat(RdDCombatManager.finalizeArmeList(armes, competences, actorData.data.carac)); @@ -614,11 +626,13 @@ export class RdDCombat { const defenderTokenId = event.currentTarget.attributes['data-defenderTokenId']?.value; const armeParadeId = event.currentTarget.attributes['data-armeid']?.value; + const competence = event.currentTarget.attributes['data-competence']?.value; + const compId = event.currentTarget.attributes['data-compid']?.value; switch (button) { case '#particuliere-attaque': return await this.choixParticuliere(attackerRoll, event.currentTarget.attributes['data-mode'].value); - case '#parer-button': return this.parade(attackerRoll, armeParadeId); - case '#esquiver-button': return this.esquive(attackerRoll); + case '#parer-button': return this.parade(attackerRoll, armeParadeId, competence); + case '#esquiver-button': return this.esquive(attackerRoll, compId, competence); case '#encaisser-button': return this.encaisser(attackerRoll, defenderTokenId); case '#echec-total-attaque': return this._onEchecTotal(attackerRoll); @@ -860,7 +874,7 @@ export class RdDCombat { await this._sendMessageDefense(attackerRoll, defenderRoll); } } - + /* -------------------------------------------- */ isPossession( attackerRoll) { return attackerRoll.selectedCarac.label.toLowerCase() == 'possession'; @@ -876,18 +890,18 @@ export class RdDCombat { } // # utilisation esquive - const esquive = Misc.data(this.defender.getCompetence("esquive")); - const corpsACorps = Misc.data(this.defender.getCompetence("Corps à corps")); - const esquiveUsage = esquive ? this.defender.getItemUse(esquive._id) : 0; + const corpsACorps = Misc.data(this.defender.getCompetence("Corps à corps", { onMessage: it => console.info(it, this.defender) })); + const esquives = duplicate(this.defender.getCompetences("esquive", { onMessage: it => console.info(it, this.defender) }).map(c => Misc.data(c))); + esquives.forEach(e => e.usages = e?.id ? this.defender.getItemUse(e.id) : 0); const paramChatDefense = { passeArme: attackerRoll.passeArme, essais: attackerRoll.essais, - isPossession: this.isPossession( attackerRoll), + isPossession: this.isPossession(attackerRoll), defender: Misc.data(this.defender), attacker: Misc.data(this.attacker), attackerId: this.attackerId, - esquiveUsage: esquiveUsage, + esquives: esquives, defenderTokenId: this.defenderTokenId, mainsNues: attackerRoll.dmg.mortalite != 'mortel' && corpsACorps, armes: this._filterArmesParade(this.defender, attackerRoll.competence, attackerRoll.arme), @@ -1002,12 +1016,12 @@ export class RdDCombat { } /* -------------------------------------------- */ - async parade(attackerRoll, armeParadeId) { + async parade(attackerRoll, armeParadeId, competence) { let arme = this.defender.getArmeParade(armeParadeId); console.log("RdDCombat.parade >>>", attackerRoll, armeParadeId, arme); - let rollData = this._prepareParade(attackerRoll, arme); + let rollData = this._prepareParade(attackerRoll, arme, competence); const dialog = await RdDRoll.create(this.defender, rollData, { @@ -1030,20 +1044,16 @@ export class RdDCombat { } /* -------------------------------------------- */ - _prepareParade(attackerRoll, armeParade) { - const compName = armeParade.data.competence; - const armeAttaque = attackerRoll.arme; - const parade = Misc.data(this.defender.getCompetence(compName)); - + _prepareParade(attackerRoll, armeParade, competenceParade) { let defenderRoll = { passeArme: attackerRoll.passeArme, diffLibre: attackerRoll.diffLibre, attackerRoll: attackerRoll, - competence: parade, + competence: Misc.data(this.defender.getCompetence(competenceParade)), arme: armeParade, surprise: this.defender.getSurprise(true), needParadeSignificative: ReglesOptionelles.isUsing('categorieParade') && RdDItemArme.needParadeSignificative(armeAttaque, armeParade), - needResist: RdDItemArme.needArmeResist(armeAttaque, armeParade), + needResist: RdDItemArme.needArmeResist(attackerRoll.arme, armeParade), carac: Misc.templateData(this.defender).carac, show: {} }; @@ -1089,10 +1099,10 @@ export class RdDCombat { } /* -------------------------------------------- */ - async esquive(attackerRoll) { - const esquive = Misc.data(this.defender.getCompetence("esquive")); + async esquive(attackerRoll, compId, compName) { + const esquive = Misc.data(this.defender.getCompetence(compId) ?? this.defender.getCompetence(compName)); if (esquive == undefined) { - ui.notifications.error(this.defender.name + " n'a pas de compétence 'esquive'"); + ui.notifications.error(this.defender.name + " n'a pas de compétence " + compName); return; } console.log("RdDCombat.esquive >>>", attackerRoll, esquive); diff --git a/templates/actor-sheet.html b/templates/actor-sheet.html index 37d0aca9..ada11fbb 100644 --- a/templates/actor-sheet.html +++ b/templates/actor-sheet.html @@ -274,21 +274,38 @@ +dom {{#each combat as |arme key|}} -
  • - {{arme.name}} - {{arme.data.initiative}} +
  • + + + {{#if arme.img}} + + {{/if}} + {{arme.name}} + + + {{arme.data.initiative}} {{arme.data.competence}} {{numberFormat arme.data.niveau decimals=0 sign=true}} - {{numberFormat arme.data.dommages decimals=0 sign=true}} + {{numberFormat arme.data.dommagesReels decimals=0 sign=true}}
  • {{/each}} -
  • - {{esquive.name}} - - - {{numberFormat esquive.niveau decimals=0 sign=true}} - -
  • + {{#each esquives as |esq key|}} +
  • + + + + {{esq.name}} + {{log esq}} + + + + + {{numberFormat esq.data.niveau decimals=0 sign=true}} + +
  • + {{/each}} +
    {{!-- Liste de blessures --}} @@ -650,7 +667,7 @@ {{/each}} -

    Montures

    +

    Compagnons animaux