diff --git a/README.md b/README.md index 25eac353..05caae68 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,8 @@ Pseudo : LeRatierBretonnien Mainteneur/Développeur : LeRatierBretonnien Développeur : VincentVk -Tests, Compendiums, Données: Fred, Fab, Grendel -Styles/CSS : Mandar +Tests, Compendiums, Données: Fred, Fab, Grendel, LeRatierBretonnien, VincentVk +Styles/CSS : Mandar, VincentVk # Mentions Légales @@ -23,6 +23,6 @@ La carte des Terres Médianes du Rêve est une illustration de **Jidus**, utilis Les silhouettes des créatures, humanoïdes et entités sont des illustrations de **Roland Barthélémy**, et sont utilisés dans le cadre de ce projet avec son aimable autorisation. Merci à eux !! -Toute la propriété intellectuelle leur appartient, ce système est une adpatation destinée à fonctionner sous FoundryVTT. +Toute la propriété intellectuelle leur appartient, ce système est une adaptation destinée à fonctionner sous FoundryVTT. L'ensemble du code est sous licence Creative Commons. \ No newline at end of file diff --git a/assets/actions/weak.svg b/assets/actions/weak.svg new file mode 100644 index 00000000..d6e79fac --- /dev/null +++ b/assets/actions/weak.svg @@ -0,0 +1,66 @@ + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/changelog.md b/changelog.md index 21df76f5..33cc1758 100644 --- a/changelog.md +++ b/changelog.md @@ -3,6 +3,19 @@ ## 13.0.9 - Le combat d'Illysis - Fix - La montée en TMR fonctionne +- Nouvelle fenêtre de jets de dés + - avancement du mode attaque + - choix de tactique + - choix des dommages mortel/non-mortel, affichage + - affichage du statut de surprise de l'attaquant + - affichage du statut de surprise du défenseur + - prise en compte des significatives (force insuffisante, demi-surprises) + - avancement du mode défense + - sélection esquive/parade + - affichage du statut de surprise du défenseur + - prise en compte des significatives (demi-surprises, armes disparates, + force insuffisante, particulière en finesse) + ## 13.0.8 - Le renouveau d'Illysis diff --git a/css/foundryvtt-reve-de-dragon.css b/css/foundryvtt-reve-de-dragon.css index 25b4833c..a203b46f 100644 --- a/css/foundryvtt-reve-de-dragon.css +++ b/css/foundryvtt-reve-de-dragon.css @@ -526,6 +526,7 @@ select, grid-area: selection; display: flex; flex-direction: row; + margin: 0.1rem 0; } .system-foundryvtt-reve-de-dragon .roll-dialog roll-choix roll-section roll-part-img { display: flex; @@ -549,11 +550,20 @@ select, .system-foundryvtt-reve-de-dragon .roll-dialog roll-choix roll-section roll-part-detail subline { display: flex; flex-direction: row; + margin: 0.1rem 0; } .system-foundryvtt-reve-de-dragon .roll-dialog roll-choix roll-section roll-part-detail subline div.poesie-extrait { display: flex; flex-direction: column; } +.system-foundryvtt-reve-de-dragon .roll-dialog roll-choix roll-section roll-part-detail subline span.status-surprise { + display: flex; + flex-direction: row; + flex-flow: wrap; +} +.system-foundryvtt-reve-de-dragon .roll-dialog roll-choix roll-section roll-part-detail subline span.status-surprise img { + filter: invert(0.8); +} .system-foundryvtt-reve-de-dragon .roll-dialog roll-section selected-numeric-value { display: flow; width: 2.5rem; @@ -608,6 +618,11 @@ select, margin: 0 0.2rem; padding: 0; } +.system-foundryvtt-reve-de-dragon .roll-dialog :is(roll-choix, roll-conditions, roll-carac, roll-comp) img.button-effect-img { + max-width: 1rem; + max-height: 1rem; + margin: 0 0.1rem; +} .system-foundryvtt-reve-de-dragon .roll-dialog roll-carac select[name="select-carac"] { max-width: 6rem; } diff --git a/lang/fr.json b/lang/fr.json index 6025fa1e..26e9a883 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -66,6 +66,7 @@ "StatusRestrained": "Immobilisé", "StatusComma": "Comma", "StatusDead": "Mort", - "StatusDemiReve": "Demi-rêve" + "StatusDemiReve": "Demi-rêve", + "StatusForceWeak": "Force insuffisante" } } \ No newline at end of file diff --git a/less/roll-dialog.less b/less/roll-dialog.less index 891320aa..c550aeb6 100644 --- a/less/roll-dialog.less +++ b/less/roll-dialog.less @@ -83,11 +83,14 @@ gap: 0.2rem; align-items: start; + subline { grid-area: selection; display: flex; flex-direction: row; + margin: 0.1rem 0; } + roll-part-img { display: flex; flex-direction: column; @@ -110,10 +113,19 @@ subline { display: flex; flex-direction: row; + margin: 0.1rem 0; div.poesie-extrait{ display: flex; flex-direction: column; } + span.status-surprise{ + display: flex; + flex-direction: row; + flex-flow: wrap; + img { + filter: invert(0.8); + } + } } } } @@ -178,6 +190,11 @@ margin: 0 0.2rem; padding: 0; } + img.button-effect-img { + max-width: 1rem; + max-height: 1rem; + margin: 0 0.1rem; + } } roll-carac select[name="select-carac"] { diff --git a/module/actor-sheet.js b/module/actor-sheet.js index 199e250f..31da145b 100644 --- a/module/actor-sheet.js +++ b/module/actor-sheet.js @@ -49,7 +49,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet { }); foundry.utils.mergeObject(formData.calc, { surenc: this.actor.computeMalusSurEncombrement(), - surprise: RdDBonus.find(this.actor.getSurprise(false)).descr, + surprise: RdDBonus.find(this.actor.getSurprise(false)).label, resumeBlessures: this.actor.computeResumeBlessure(this.actor.system.blessures), caracTotal: RdDCarac.computeTotal(this.actor.system.carac, this.actor.system.beaute), surEncombrementMessage: this.actor.isSurenc() ? "Sur-Encombrement!" : "", diff --git a/module/actor-token.mjs b/module/actor-token.mjs index f61371c1..465e98e8 100644 --- a/module/actor-token.mjs +++ b/module/actor-token.mjs @@ -31,7 +31,7 @@ export class ActorToken { constructor(token) { this.name = token.name ?? token.actor.name - this.img = token.texture.src ?? token.actor.img + this.img = token.actor.isToken && token.texture.src ? token.texture.src : token.actor.img this.actor = token.actor this.id = token.actor?.id this.token = token diff --git a/module/actor.js b/module/actor.js index 2d8181fa..37bc8113 100644 --- a/module/actor.js +++ b/module/actor.js @@ -14,7 +14,7 @@ import { STATUSES } from "./settings/status-effects.js"; import { ReglesOptionnelles } from "./settings/regles-optionnelles.js"; import { EffetsDraconiques } from "./tmr/effets-draconiques.js"; import { Draconique } from "./tmr/draconique.js"; -import { LIST_CARAC_PERSONNAGE, RdDCarac } from "./rdd-carac.js"; +import { CARACS, LIST_CARAC_PERSONNAGE, RdDCarac } from "./rdd-carac.js"; import { DialogConsommer } from "./dialog-item-consommer.js"; import { DialogFabriquerPotion } from "./dialog-fabriquer-potion.js"; import { RollDataAjustements } from "./rolldata-ajustements.js"; @@ -31,9 +31,8 @@ import { ITEM_TYPES } from "./constants.js"; import { RdDBaseActorSang } from "./actor/base-actor-sang.js"; import { RdDCoeur } from "./coeur/rdd-coeur.js"; import { DialogChoixXpCarac } from "./dialog-choix-xp-carac.js"; -import { RdDCombatManager } from "./rdd-combat.js"; -import { RdDItemArme } from "./item/arme.js"; +import { ATTAQUE_TYPE, RdDItemArme } from "./item/arme.js"; import { RdDItemBlessure } from "./item/blessure.js"; import { RdDItemTete } from "./item/tete.js"; import { RdDItemSort } from "./item-sort.js"; @@ -167,63 +166,63 @@ export class RdDActor extends RdDBaseActorSang { .find(it => true) } - /* -------------------------------------------- */ - /** Retourne une liste triée d'actions d'armes avec le split arme1 main / arme 2 main / lancer */ - listActionsAttaque() { - let actions = [ - this.$prepareAttaqueArme(RdDItemArme.empoignade(this)), - this.$prepareAttaqueArme(RdDItemArme.corpsACorps(this)), - ] - - const armes = this.itemTypes[ITEM_TYPES.arme] - .filter(it => RdDItemArme.isAttaque(it)) - .sort(Misc.ascending(it => it.name)); - - for (const arme of armes) { - if (arme.system.unemain && arme.system.competence) { - actions.push(this.$prepareAttaqueArme(arme, '(1 main)')) - } - if (arme.system.deuxmains && arme.system.competence) { - actions.push(this.$prepareAttaqueArme(arme, '(2 mains)')) - } - if (arme.system.lancer) { - actions.push(this.$prepareAttaqueArme(arme, '(lancer)')) - } - if (arme.system.tir) { - actions.push(this.$prepareAttaqueArme(arme, '(tir)')) - } - } - return actions; + isForceInsuffisante(forceRequise) { + const force = parseInt(this.system.carac.force.value) + return forceRequise > force } /* -------------------------------------------- */ - $prepareAttaqueArme(arme, main) { - const comp = this.getCompetence(RdDActor.$getCompetenceAction(arme, main)) - const caracCode = RdDActor.$getCaracAction(comp, main) - const caracValue = this.system.carac[caracCode].value - const dommages = arme.system.dommages.toString() + /** Retourne une liste triée d'actions d'armes avec le split arme1 main / arme 2 main / lancer */ + listActionsAttaque() { + const actions = [] + const uniques = [] - // TODO: déplacer sur RdDItemArme - 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)`) - } - const tableauDommages = dommages.includes("/") ? dommages.split("/") : [dommages, dommages] - const dmg = main == '(2 mains)' ? tableauDommages[1] : tableauDommages[0] - const niveau = comp?.system.niveau ?? (['(lancer)', '(tir)'].includes(main) ? -8 : -6) - const ajustement = (arme.parent?.getEtatGeneral() ?? 0) + (arme.system.magique) ? arme.system.ecaille_efficacite : 0 + const addAttaque = (arme, main) => { + const dommagesArme = RdDItemArme.valeurMain(arme.system.dommages, main) + const forceRequise = RdDItemArme.valeurMain(arme.system.force ?? 0, main) + const ecaillesEfficacite = arme.system.magique ? arme.system.ecaille_efficacite : 0; - return { - name: arme.name + (main ? ' ' + main : ''), - action: 'attaque', - initOnly: false, - arme: arme, - comp: comp, - main: main, - carac: { key: caracCode, value: caracValue }, - equipe: arme.system.equipe, - dmg: dmg, - initiative: RdDInitiative.calculInitiative(niveau, caracValue, ajustement) + const comp = this.getCompetence(RdDActor.$getCompetenceAction(arme, main)) + const unique = [comp.id, arme.name, dommagesArme, forceRequise, ecaillesEfficacite].join('|'); + if (uniques.includes(unique)) { + return + } + uniques.push(unique); + + const caracCode = RdDActor.$getCaracAction(comp, main) + const caracValue = this.system.carac[caracCode].value + + const niveau = comp?.system.niveau ?? (['(lancer)', '(tir)'].includes(main) ? -8 : -6) + const ajustement = (arme.parent?.getEtatGeneral() ?? 0) + ecaillesEfficacite + + actions.push({ + name: arme.name + (main ? ' ' + main : ''), + action: 'attaque', + initOnly: false, + arme: arme, + comp: comp, + main: main, + carac: { key: caracCode, value: caracValue }, + equipe: arme.system.equipe, + dommagesArme: dommagesArme, + forceRequise: forceRequise, + initiative: RdDInitiative.calculInitiative(niveau, caracValue, ajustement) + }) } + + addAttaque(RdDItemArme.empoignade(this)) + addAttaque(RdDItemArme.corpsACorps(this)) + + this.itemTypes[ITEM_TYPES.arme] + .filter(it => it.isAttaque()) + .sort(Misc.ascending(it => it.name)) + .forEach(arme => { + if (arme.system.unemain && arme.system.competence) { addAttaque(arme, ATTAQUE_TYPE.UNE_MAIN) } + if (arme.system.deuxmains && arme.system.competence) { addAttaque(arme, ATTAQUE_TYPE.DEUX_MAINS) } + if (arme.system.lancer) { addAttaque(arme, ATTAQUE_TYPE.LANCER) } + if (arme.system.tir) { addAttaque(arme, ATTAQUE_TYPE.TIR) } + }) + return actions } static $getCaracAction(comp, main) { @@ -239,10 +238,10 @@ export class RdDActor extends RdDBaseActorSang { static $getCompetenceAction(arme, main) { switch (main) { - case '(1 main)': return arme.competence1Mains() - case '(2 mains)': return arme.competence2Mains() - case '(lancer)': return arme.system.lancer - case '(tir)': return arme.system.tir + case ATTAQUE_TYPE.UNE_MAIN: return arme.competence1Mains() + case ATTAQUE_TYPE.DEUX_MAINS: return arme.competence2Mains() + case ATTAQUE_TYPE.LANCER: return arme.system.lancer + case ATTAQUE_TYPE.TIR: return arme.system.tir default: return arme.system.competence } } @@ -2278,13 +2277,12 @@ export class RdDActor extends RdDBaseActorSang { static _getComposantsCaracDerivee(caracName) { switch (Grammar.toLowerCaseNoAccent(caracName)) { - case 'reve-actuel': case 'reve actuel': return ['reve'] - case 'chance-actuelle': case 'chance actuelle': return ['chance'] - case 'vie': return ['constitution'] - case 'tir': return ['vue', 'dexterite'] - case 'lancer': return ['force', 'dexterite', 'vue'] - case 'melee': return ['force', 'agilite'] - case 'derobee': return ['agilite'] + case CARACS.REVE_ACTUEL: case 'reve actuel': return [CARACS.REVE] + case CARACS.CHANCE_ACTUELLE: case 'chance actuelle': return [CARACS.CHANCE] + case CARACS.TIR: return [CARACS.DEXTERITE, CARACS.VUE] + case CARACS.LANCER: return [CARACS.FORCE, CARACS.DEXTERITE, CARACS.VUE] + case CARACS.MELEE: return [CARACS.FORCE, CARACS.AGILITE] + case CARACS.DEROBEE: return [CARACS.AGILITE] } return [] } @@ -3249,3 +3247,4 @@ export class RdDActor extends RdDBaseActorSang { } } + diff --git a/module/actor/base-actor-reve.js b/module/actor/base-actor-reve.js index b3311ec5..98974363 100644 --- a/module/actor/base-actor-reve.js +++ b/module/actor/base-actor-reve.js @@ -14,9 +14,9 @@ import { RdDConfirm } from "../rdd-confirm.js"; import { RdDCarac } from "../rdd-carac.js"; import { RdDRollResult } from "../rdd-roll-result.js"; +import { RdDItemArme } from "../item/arme.js"; import { RdDItemCompetence } from "../item-competence.js"; import { RdDItemCompetenceCreature } from "../item-competencecreature.js"; -import { RdDItemArme } from "../item/arme.js"; import { ChatUtility } from "../chat-utility.js"; import { DialogValidationEncaissement } from "../dialog-validation-encaissement.js"; @@ -80,7 +80,7 @@ export class RdDBaseActorReve extends RdDBaseActor { getBonusDegat() { return RdDCarac.getCaracDerivee(this.getEncombrementMax()).plusdom } getMoralTotal() { return 0 } - listeAmoureux() {return []} + listeAmoureux() { return [] } getProtectionNaturelle() { return Number(this.system.attributs?.protection?.value ?? 0) } getSConst() { return 0 } @@ -113,7 +113,7 @@ export class RdDBaseActorReve extends RdDBaseActor { listActions({ isAttaque = false, isEquipe = false }) { return this.itemTypes[ITEM_TYPES.competencecreature] - .filter(it => RdDItemCompetenceCreature.isAttaque(it)) + .filter(it => it.isAttaque()) .map(it => RdDItemCompetenceCreature.attaqueCreature(it)) .filter(it => it != undefined); } @@ -191,6 +191,10 @@ export class RdDBaseActorReve extends RdDBaseActor { return RdDItemArme.getArme(armeParadeId ? this.getEmbeddedDocument('Item', armeParadeId) : undefined) } + isForceInsuffisante(forceRequise) { + return false + } + getDraconicOuPossession() { return POSSESSION_SANS_DRACONIC } getPossession(possessionId) { @@ -222,8 +226,13 @@ export class RdDBaseActorReve extends RdDBaseActor { /* -------------------------------------------- */ isEffectAllowed(effectId) { return false } - getEffects(filter = e => true) { - return this.getEmbeddedCollection("ActiveEffect").filter(filter); + getEffects(filter = e => true, forceRequise = undefined) { + const effects = this.getEmbeddedCollection("ActiveEffect").filter(filter) + if (forceRequise && this.isForceInsuffisante(forceRequise)) { + /// TODO + effects.push(StatusEffects.prepareActiveEffect(STATUSES.StatusForceWeak)) + } + return effects } getEffectByStatus(statusId) { @@ -259,11 +268,7 @@ export class RdDBaseActorReve extends RdDBaseActor { } getSurprise(isCombat = undefined) { - return StatusEffects.typeSurprise( - this.getEffects() - .map(it => StatusEffects.niveauSurprise(it, isCombat)) - .reduce(Misc.sum(), 0) - ) + return StatusEffects.getSurprise(this.getEffects(), isCombat) } /* -------------------------------------------- */ diff --git a/module/actor/base-actor-sheet.js b/module/actor/base-actor-sheet.js index 37e6cc8b..d632dad3 100644 --- a/module/actor/base-actor-sheet.js +++ b/module/actor/base-actor-sheet.js @@ -5,7 +5,6 @@ import { RdDSheetUtility } from "../rdd-sheet-utility.js"; import { Monnaie } from "../item-monnaie.js"; import { ITEM_TYPES } from "../constants.js"; import { RdDItem } from "../item.js"; -import { RdDItemCompetenceCreature } from "../item-competencecreature.js"; import { RdDTextEditor } from "../apps/rdd-text-roll-editor.js"; import { ItemAction } from "../item/item-actions.js"; @@ -56,7 +55,7 @@ export class RdDBaseActorSheet extends foundry.appv1.sheets.ActorSheet { this._appliquerRechercheObjets(formData.conteneurs, formData.inventaires); formData.conteneurs = RdDUtility.conteneursRacine(formData.conteneurs); formData.competences.filter(it => it.type == ITEM_TYPES.competencecreature) - .forEach(it => it.isdommages = RdDItemCompetenceCreature.isDommages(it)) + .forEach(it => it.isdommages = it.isDommages()) return formData; } diff --git a/module/item-competencecreature.js b/module/item-competencecreature.js index 6beb4ac3..08a45313 100644 --- a/module/item-competencecreature.js +++ b/module/item-competencecreature.js @@ -1,126 +1,78 @@ - import { ITEM_TYPES } from "./constants.js"; -import { Grammar } from "./grammar.js"; -import { RdDInitiative } from "./initiative.mjs"; import { RdDItem } from "./item.js"; - -export const CATEGORIES_COMPETENCES_CREATURES = { - "generale": { base: 0, label: "Générale" }, - "naturelle": { base: 0, label: "Arme naturelle" }, - "melee": { base: 0, label: "Mêlée" }, - "parade": { base: 0, label: "Parade" }, - "tir": { base: 0, label: "Tir" }, - "lancer": { base: 0, label: "Lancer" }, - "possession": { base: 0, label: "Possession" }, -} +import { RdDInitiative } from "./initiative.mjs"; /* -------------------------------------------- */ -export class RdDItemCompetenceCreature extends Item { +export class RdDItemCompetenceCreature extends RdDItem { - /* -------------------------------------------- */ - static setRollDataCreature(rollData) { - const code = Grammar.toLowerCaseNoAccentNoSpace(rollData.competence.name); - const selectedCarac = { code: code, label: rollData.competence.name, value: rollData.competence.system.carac_value }; - rollData.carac = { [code]: selectedCarac } - rollData.competence.system.defaut_carac = code - rollData.selectedCarac = selectedCarac - rollData.arme = RdDItemCompetenceCreature.armeCreature(rollData.competence); - } + static get ITEM_TYPE() { return ITEM_TYPES.competencecreature } - /* -------------------------------------------- */ - static armeCreature(item) { - const categorieAttaque = RdDItemCompetenceCreature.getCategorieAttaque(item) + static get defaultIcon() { return "systems/foundryvtt-reve-de-dragon/icons/competence_defaut.webp" } + + isParade() { return this.system.iscombat && (this.system.categorie_parade ?? '') != '' } + isBouclier() { return this.system.categorie_parade.includes('bouclier') } + + static attaqueCreature(comp) { + const categorieAttaque = comp.getCategorieAttaque() if (categorieAttaque != undefined) { - // cloner pour ne pas modifier la compétence - return foundry.utils.mergeObject(item, { - action: item.isCompetencePossession() ? 'possession' : 'attaque', + const initative = RdDInitiative.calculInitiative(comp.system.niveau, comp.system.carac_value); + const armeComp = new RdDItem({ + name: comp.name, + type: ITEM_TYPES.arme, + img: comp.img, system: { - competence: item.name, + competence: comp.name, cac: categorieAttaque == "naturelle" ? "naturelle" : "", - niveau: item.system.niveau, - initiative: RdDInitiative.calculInitiative(item.system.niveau, item.system.carac_value), + niveau: comp.system.niveau, + initiative: initative, + mortalite: comp.system.mortalite, + dommages: comp.system.dommages, equipe: true, resistance: 100, - dommagesReels: item.system.dommages, penetration: 0, force: 0, rapide: true, } - }, { inplace: false, }); - } - return undefined; - } - static attaqueCreature(comp) { - const categorieAttaque = RdDItemCompetenceCreature.getCategorieAttaque(comp) - if (categorieAttaque != undefined) { - const initative = RdDInitiative.calculInitiative(comp.system.niveau, comp.system.carac_value); - return { + }); + const attaque = { name: comp.name, action: comp.isCompetencePossession() ? 'possession' : 'attaque', initOnly: false, - arme: new RdDItem({ - name: comp.name, - type: ITEM_TYPES.arme, - img: comp.img, - system: { - competence: comp.name, - cac: categorieAttaque == "naturelle" ? "naturelle" : "", - niveau: comp.system.niveau, - initiative: initative, - equipe: true, - resistance: 100, - dommagesReels: comp.system.dommages, - penetration: 0, - force: 0, - rapide: true, - } - }), + arme: armeComp, comp: comp, - // main: '', carac: { key: comp.name, value: comp.system.carac_value }, equipe: true, + mortalite: comp.system.mortalite, dmg: comp.system.dommages, initiative: initative - } + }; + return attaque } return undefined; } - /* -------------------------------------------- */ - static isAttaque(item) { - return RdDItemCompetenceCreature.getCategorieAttaque(item) != undefined + isAttaque() { + return this.getCategorieAttaque() != undefined } - static getCategorieAttaque(item) { - if (item.type == ITEM_TYPES.competencecreature) { - switch (item.system.categorie) { - case "melee": - case "tir": - case "lancer": - case "naturelle": - case "possession": - return item.system.categorie - } + getCategorieAttaque() { + switch (this.system.categorie) { + case "melee": + case "tir": + case "lancer": + case "naturelle": + case "possession": + return this.system.categorie } - return undefined } - static isDommages(item) { - if (item.type == ITEM_TYPES.competencecreature) { - switch (item.system.categorie) { - case "melee": - case "tir": - case "lancer": - case "naturelle": - return true - } - } - return false - } - - static isParade(item) { - if (item.type == ITEM_TYPES.competencecreature) { - return item.system.categorie_parade || item.system.isparade + isDommages() { + switch (this.system.categorie) { + case "melee": + case "tir": + case "lancer": + case "naturelle": + return true } return false } diff --git a/module/item-sheet.js b/module/item-sheet.js index 42bb0a2b..264c4024 100644 --- a/module/item-sheet.js +++ b/module/item-sheet.js @@ -9,7 +9,6 @@ import { RdDSheetUtility } from "./rdd-sheet-utility.js"; import { SystemCompendiums } from "./settings/system-compendiums.js"; import { Misc } from "./misc.js"; import { RdDTimestamp } from "./time/rdd-timestamp.js"; -import { RdDItemCompetenceCreature } from "./item-competencecreature.js"; import { RdDItem } from "./item.js"; import { FLEUVE_COORD, TMRUtility } from "./tmr-utility.js"; import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js"; @@ -106,8 +105,8 @@ export class RdDItemSheetV1 extends foundry.appv1.sheets.ItemSheet { } if (this.item.type == ITEM_TYPES.competencecreature) { - formData.isparade = RdDItemCompetenceCreature.isParade(this.item) - formData.isdommages = RdDItemCompetenceCreature.isDommages(this.item) + formData.isparade = this.item.isParade() + formData.isdommages = this.item.isDommages() } if (this.item.type == ITEM_TYPES.tache || this.item.type == ITEM_TYPES.livre || diff --git a/module/item.js b/module/item.js index 64a01f3f..32426eae 100644 --- a/module/item.js +++ b/module/item.js @@ -1,4 +1,7 @@ import { ITEM_TYPES } from "./constants.js"; +import { CATEGORIES_COMPETENCES } from "./item-competence.js"; +import { BASE_CORPS_A_CORPS, BASE_ESQUIVE, CATEGORIES_COMPETENCES_CREATURES } from "./item/base-items.js"; +import { ITEM_ACTIONS, DEFAULT_ACTIONS, COMMON_ACTIONS } from "./item/item-actions.js"; import { Grammar } from "./grammar.js"; import { Misc } from "./misc.js"; @@ -7,10 +10,6 @@ import { RdDTimestamp } from "./time/rdd-timestamp.js"; import { RdDUtility } from "./rdd-utility.js"; import { SystemCompendiums } from "./settings/system-compendiums.js"; import { RdDRaretes } from "./item/raretes.js"; -import { CATEGORIES_COMPETENCES } from "./item-competence.js"; -import { CATEGORIES_COMPETENCES_CREATURES } from "./item-competencecreature.js"; -import { BASE_CORPS_A_CORPS, BASE_ESQUIVE } from "./item/base-items.js"; -import { ITEM_ACTIONS, DEFAULT_ACTIONS, COMMON_ACTIONS } from "./item/item-actions.js"; const typesInventaireMateriel = [ ITEM_TYPES.arme, @@ -186,7 +185,10 @@ export class RdDItem extends Item { isMonnaie() { return this.type == ITEM_TYPES.monnaie; } isNourritureBoisson() { return this.type == ITEM_TYPES.nourritureboisson; } isService() { return this.type == ITEM_TYPES.service; } - + isAttaque() { return false } + isParade() { return false } + isBouclier() { return false } + getCategorieAttaque() { return undefined } isCompetence() { return typesObjetsCompetence.includes(this.type) } isEsquive() { return (this.isCompetence() diff --git a/module/item/arme.js b/module/item/arme.js index ed36fbb2..894e7881 100644 --- a/module/item/arme.js +++ b/module/item/arme.js @@ -1,10 +1,9 @@ import { ITEM_TYPES } from "../constants.js"; import { RdDItem } from "../item.js"; - -import { RdDItemCompetenceCreature } from "../item-competencecreature.js" import { BASE_CORPS_A_CORPS } from "./base-items.js"; import { Grammar } from "../grammar.js"; import { RdDInitiative } from "../initiative.mjs"; +import { MappingCreatureArme } from "./mapping-creature-arme.mjs"; const nomCategorieParade = { "sans-armes": "Sans arme", @@ -19,24 +18,48 @@ const nomCategorieParade = { "haches": "Haches", "lances": "Lances", } - +export const ATTAQUE_TYPE = { + UNE_MAIN: '(1 main)', + DEUX_MAINS: '(2 mains)', + COMPETENCE: 'competence', + TIR: '(tir)', + LANCER: '(lancer)' +} /* -------------------------------------------- */ export class RdDItemArme extends RdDItem { static get ITEM_TYPE() { return ITEM_TYPES.arme } - static get defaultIcon() { - return defaultItemImgArme - //return "systems/foundryvtt-reve-de-dragon/icons/armes_armure/epee_sord.webp"; - } + static get defaultIcon() { return "systems/foundryvtt-reve-de-dragon/icons/armes_armures/epee_gnome.webp" } + + penetration() { return parseInt(this.system.penetration ?? 0) } + + isParade() { return this.system.resistance > 0 && this.system.categorie_parade } + isBouclier() { return RdDItemArme.getCategorieParade(this).includes('bouclier') } /* -------------------------------------------- */ + static valeurMain(valeurs, main) { + valeurs = valeurs?.toString() ?? "" + const table = valeurs.includes("/") ? valeurs.split("/") : [valeurs, valeurs] + return parseInt(main == ATTAQUE_TYPE.DEUX_MAINS ? table[1] : table[0]) + } + + static getMainAttaque(competence) { + switch (competence.system.categorie) { + case 'tir': return ATTAQUE_TYPE.TIR + case 'lancer': return ATTAQUE_TYPE.LANCER + } + if (competence.name.includes('2 main')) { + return ATTAQUE_TYPE.DEUX_MAINS + } + return ATTAQUE_TYPE.UNE_MAIN + } static getArme(arme) { switch (arme ? arme.type : '') { case ITEM_TYPES.arme: return arme; case ITEM_TYPES.competencecreature: - return RdDItemCompetenceCreature.armeCreature(arme); + return MappingCreatureArme.armeCreature(arme); } return RdDItemArme.corpsACorps(); } @@ -47,11 +70,11 @@ export class RdDItemArme extends RdDItem { return arme.name case ITEM_TYPES.arme: switch (maniement) { - case 'competence': return arme.system.competence; - case '(1 main)': return arme.competence1Mains() - case '(2 mains)': return arme.competence2Mains() - case '(tir)': case 'tir': return arme.system.tir - case '(lancer)': case 'lancer': return arme.system.lancer; + case ATTAQUE_TYPE.COMPETENCE: return arme.system.competence; + case ATTAQUE_TYPE.UNE_MAIN: return arme.competence1Mains() + case ATTAQUE_TYPE.DEUX_MAINS: return arme.competence2Mains() + case ATTAQUE_TYPE.TIR: case 'tir': return arme.system.tir + case ATTAQUE_TYPE.LANCER: case 'lancer': return arme.system.lancer; } } return undefined @@ -88,16 +111,13 @@ export class RdDItemArme extends RdDItem { /* -------------------------------------------- */ static getCategorieParade(armeData) { + if (![ITEM_TYPES.arme, ITEM_TYPES.competencecreature].includes(armeData.type)) { + return '' + } if (armeData.system.categorie_parade) { return armeData.system.categorie_parade } // pour compatibilité avec des personnages existants - if (armeData.type == ITEM_TYPES.competencecreature || armeData.system.categorie == 'creature') { - return armeData.system.categorie_parade || (armeData.system.isparade ? 'armes-naturelles' : '') - } - if (!armeData.type.match(/arme|competencecreature/)) { - return '' - } if (armeData.system.competence == undefined) { return ITEM_TYPES.competencecreature; } @@ -192,7 +212,7 @@ export class RdDItemArme extends RdDItem { return Number(arme.system.dommages) } const tableauDegats = arme.system.dommages.split("/"); - return Number(tableauDegats[maniement == '(1 main)' ? 0 : 1]) + return Number(tableauDegats[maniement == ATTAQUE_TYPE.UNE_MAIN ? 0 : 1]) } return Number(arme.system.dommages); } @@ -201,7 +221,7 @@ export class RdDItemArme extends RdDItem { static armeUneOuDeuxMains(arme, aUneMain) { if (arme && !arme.system.cac) { arme = foundry.utils.duplicate(arme); - arme.system.dommagesReels = RdDItemArme.dommagesReels(arme, aUneMain ? '(1 main)' : '(2 mains)') + arme.system.dommagesReels = RdDItemArme.dommagesReels(arme, aUneMain ? ATTAQUE_TYPE.UNE_MAIN : ATTAQUE_TYPE.DEUX_MAINS) } return arme; } @@ -222,25 +242,10 @@ export class RdDItemArme extends RdDItem { return false } - static isAttaque(arme) { - switch (arme.type) { - case ITEM_TYPES.arme: return arme.system.equipe && (arme.system.resistance > 0 || arme.system.portee_courte > 0) - case ITEM_TYPES.competencecreature: return arme.system.iscombat && RdDItemCompetenceCreature.isAttaque(item) - } - return false + isAttaque() { + return this.system.resistance > 0 || this.system.portee_courte > 0 } - static isParade(arme) { - switch (arme.type) { - case ITEM_TYPES.arme: - return arme.system.resistance > 0 && true/* TODO: regarder la categorie d'arme?*/ - case ITEM_TYPES.competencecreature: - return arme.system.iscombat && RdDItemCompetenceCreature.isParade(arme) - } - return false - } - - static corpsACorps(actor) { let competence = actor?.getCompetenceCorpsACorps() ?? BASE_CORPS_A_CORPS let melee = actor ? actor.system.carac['melee'].value : 0 diff --git a/module/item/base-items.js b/module/item/base-items.js index fd1207e5..e04f285e 100644 --- a/module/item/base-items.js +++ b/module/item/base-items.js @@ -18,3 +18,12 @@ export const SANS_COMPETENCE = { img: "systems/foundryvtt-reve-de-dragon/icons/templates/icone_parchement_vierge.webp" } +export const CATEGORIES_COMPETENCES_CREATURES = { + "generale": { base: 0, label: "Générale" }, + "naturelle": { base: 0, label: "Arme naturelle" }, + "melee": { base: 0, label: "Mêlée" }, + "parade": { base: 0, label: "Parade" }, + "tir": { base: 0, label: "Tir" }, + "lancer": { base: 0, label: "Lancer" }, + "possession": { base: 0, label: "Possession" }, +} diff --git a/module/item/mapping-creature-arme.mjs b/module/item/mapping-creature-arme.mjs new file mode 100644 index 00000000..a643b6b9 --- /dev/null +++ b/module/item/mapping-creature-arme.mjs @@ -0,0 +1,42 @@ +import { Grammar } from "../grammar.js"; +import { RdDInitiative } from "../initiative.mjs"; + +export class MappingCreatureArme { + + + /* -------------------------------------------- */ + static setRollDataCreature(rollData) { + const code = Grammar.toLowerCaseNoAccentNoSpace(rollData.competence.name); + const selectedCarac = { code: code, label: rollData.competence.name, value: rollData.competence.system.carac_value }; + rollData.carac = { [code]: selectedCarac } + rollData.competence.system.defaut_carac = code + rollData.selectedCarac = selectedCarac + rollData.arme = MappingCreatureArme.armeCreature(rollData.competence); + } + + + /* -------------------------------------------- */ + static armeCreature(item) { + const categorieAttaque = item.getCategorieAttaque() + if (categorieAttaque != undefined) { + // cloner pour ne pas modifier la compétence + return foundry.utils.mergeObject(item, { + action: item.isCompetencePossession() ? 'possession' : 'attaque', + system: { + competence: item.name, + cac: categorieAttaque == "naturelle" ? "naturelle" : "", + niveau: item.system.niveau, + initiative: RdDInitiative.calculInitiative(item.system.niveau, item.system.carac_value), + equipe: true, + resistance: 100, + dommagesReels: item.system.dommages, + penetration: 0, + force: 0, + rapide: true, + } + }, { inplace: false, }); + } + return undefined; + } + +} \ No newline at end of file diff --git a/module/rdd-bonus.js b/module/rdd-bonus.js index 1d69e3ea..8fa1a4d0 100644 --- a/module/rdd-bonus.js +++ b/module/rdd-bonus.js @@ -1,21 +1,24 @@ -import { RdDCarac } from "./rdd-carac.js"; +import { RdDItemArme } from "./item/arme.js"; import { RdDPossession } from "./rdd-possession.js"; const conditionsTactiques = [ - { type: '', descr: '', dmg: 0, attaque: 0, parade: 0, esquive: true }, - { type: 'charge', descr: 'Charge', dmg: 2, attaque: 4, parade: -4, esquive: false }, - { type: 'feinte', descr: 'Feinte', dmg: 1, attaque: 1, parade: 0, esquive: true }, - { type: 'pret', descr: 'prêt', dmg: 0, attaque: 0, parade: 0, esquive: true }, - { type: 'demi', descr: 'Demi-surprise', dmg: 1, attaque: 0, parade: 0, esquive: true }, - { type: 'totale', descr: 'Surprise totale', dmg: 10, attaque: 6, parade: 0, esquive: true }, + { key: '', label: '', dmg: 0, attaque: 0, parade: 0, esquive: true, isTactique: false }, + { key: 'normale', label: 'Attaque normale', dmg: 0, attaque: 0, parade: 0, esquive: true, isTactique: true }, + { key: 'charge', label: 'Charge', dmg: 2, attaque: 4, parade: -4, esquive: false, isTactique: true }, + { key: 'feinte', label: 'Feinte', dmg: 1, attaque: 1, parade: 0, esquive: true, isTactique: true }, + { key: 'pret', label: 'prêt', dmg: 0, attaque: 0, parade: 0, esquive: true, isTactique: false }, + { key: 'demi', label: 'Demi-surprise', dmg: 1, attaque: 0, parade: 0, esquive: true, isTactique: false }, + { key: 'totale', label: 'Surprise totale', dmg: 10, attaque: 6, parade: 0, esquive: true, isTactique: false }, ]; /* -------------------------------------------- */ export class RdDBonus { - + static get tactiques() { + return conditionsTactiques.filter(it => it.isTactique) + } /* -------------------------------------------- */ static find(condition) { - return conditionsTactiques.find(e => e.type == condition) || conditionsTactiques.find(e => e.type == 'pret'); + return conditionsTactiques.find(e => e.key == condition) || conditionsTactiques[0]; } @@ -32,7 +35,8 @@ export class RdDBonus { /* -------------------------------------------- */ static dmg(rollData, actor, isEntiteIncarnee = false) { - const dmgArme = RdDBonus.dmgArme(rollData.arme) + const dmgArme = RdDBonus.dmgArme(rollData.arme, rollData.arme?.system.dommagesReels) + const forceRequise = RdDItemArme.valeurMain(rollData.arme?.system.force ?? 0, RdDItemArme.getMainAttaque(rollData.competence)) let dmg = { total: 0, dmgArme: dmgArme, @@ -41,39 +45,44 @@ export class RdDBonus { dmgParticuliere: RdDBonus._dmgParticuliere(rollData), dmgSurprise: RdDBonus.dmgBonus(rollData.ajustements?.attaqueDefenseurSurpris.used), mortalite: RdDBonus._calculMortalite(rollData, isEntiteIncarnee), - dmgActor: RdDBonus.bonusDmg(actor, rollData.selectedCarac?.label.toLowerCase(), dmgArme) + dmgActor: RdDBonus.bonusDmg(actor, rollData.selectedCarac?.label.toLowerCase(), dmgArme), + dmgForceInsuffisante: Math.min(0, actor.getForce() - forceRequise) } - dmg.total = dmg.dmgSurprise + dmg.dmgTactique + dmg.dmgArme + dmg.dmgActor + dmg.dmgParticuliere; + dmg.total = dmg.dmgSurprise + dmg.dmgTactique + dmg.dmgArme + dmg.dmgActor + dmg.dmgParticuliere + dmg.dmgForceInsuffisante return dmg; } /* -------------------------------------------- */ static description(condition) { - return RdDBonus.find(condition).descr; + return RdDBonus.find(condition).label } /* -------------------------------------------- */ static dmgBonus(condition) { - return RdDBonus.find(condition).dmg; + return RdDBonus.find(condition).dmg } /* -------------------------------------------- */ static bonusAttaque(condition) { - return RdDBonus.find(condition).attaque; + return RdDBonus.find(condition).attaque } /* -------------------------------------------- */ static _calculMortalite(rollData, isEntiteIncarnee) { + return RdDBonus.mortalite(rollData.dmg?.mortalite, rollData.arme?.system.mortalite, isEntiteIncarnee) + } + + static mortalite(mortaliteSelect, mortaliteArme, isEntiteIncarnee) { return isEntiteIncarnee ? "entiteincarnee" - : rollData.dmg?.mortalite - ?? rollData.arme?.system.mortalite + : mortaliteSelect + ?? mortaliteArme ?? "mortel"; } /* -------------------------------------------- */ - static dmgArme(arme) { + static dmgArme(arme, dommagesMain) { if (arme) { - let dmgBase = arme.system.dommagesReels ?? Number(arme.system.dommages ?? 0); + let dmgBase = dommagesMain ?? Number(arme.system.dommages ?? 0); //Le bonus dégats magiques ne peut pas faire dépasser le bonus de l'arme (cf p.278) return dmgBase + Math.min(dmgBase, arme.system.magique ? arme.system.ecaille_efficacite : 0); } @@ -87,13 +96,13 @@ export class RdDBonus { /* -------------------------------------------- */ static bonusDmg(actor, categorie, dmgArme) { - const dmgActor = actor.getBonusDegat() if (categorie == undefined) { return 0 } + const dmgActor = actor.getBonusDegat() switch (categorie) { - case "tir": return 0; - case "lancer": return Math.max(0, Math.min(dmgArme, dmgActor)); + case "(tir)": case "tir": return 0 + case "(lancer)": case "lancer": return Math.max(0, Math.min(dmgArme, dmgActor)); } return dmgActor; } diff --git a/module/rdd-carac.js b/module/rdd-carac.js index 55cb879f..76a89fd6 100644 --- a/module/rdd-carac.js +++ b/module/rdd-carac.js @@ -52,6 +52,15 @@ export const CARACS = { EMPATHIE: 'empathie', REVE: 'reve', CHANCE: 'chance', + PROTECTION: 'protection', + BEAUTE: 'beaute', + PERCEPTION: 'perception', + MELEE: 'melee', + TIR: 'tir', + LANCER: 'lancer', + DEROBEE: 'derobee', + CHANCE_ACTUELLE: 'chance-actuelle', + REVE_ACTUEL: 'reve-actuel', } export const LIST_CARAC_PERSONNAGE = { [CARACS.TAILLE]: { code: CARACS.TAILLE, label: 'Taille', isCarac: true, path: 'system.carac.taille.value' }, @@ -68,21 +77,21 @@ export const LIST_CARAC_PERSONNAGE = { [CARACS.EMPATHIE]: { code: CARACS.EMPATHIE, label: 'Empathie', isCarac: true, path: 'system.carac.empathie.value' }, [CARACS.REVE]: { code: CARACS.REVE, label: 'Rêve', isCarac: true, path: 'system.carac.reve.value' }, [CARACS.CHANCE]: { code: CARACS.CHANCE, label: 'Chance', isCarac: true, path: 'system.carac.chance.value' }, - 'protection': { code: 'protection', label: 'Protection naturelle', isCarac: false, path: 'system.attributs.protection.value' }, - 'beaute': { code: 'beaute', label: 'Beauté', isCarac: false, path: 'system.background.beaute.value' } + [CARACS.PROTECTION]: { code: CARACS.PROTECTION, label: 'Protection naturelle', isCarac: false, path: 'system.attributs.protection.value' }, + [CARACS.BEAUTE]: { code: CARACS.BEAUTE, label: 'Beauté', isCarac: false, path: 'system.background.beaute.value' } } export const LIST_CARAC_AUTRES = { - 'perception': { code: 'perception', label: 'Perception', path: 'system.carac.perception.value' }, + [CARACS.PERCEPTION]: { code: 'perception', label: 'Perception', path: 'system.carac.perception.value' }, } const LIST_CARAC_DERIVEE = { - 'melee': { code: "melee", label: 'Mêlée', path: 'system.carac.melee.value' }, - 'tir': { code: "tir", label: 'Tir', path: 'system.carac.tir.value' }, - 'lancer': { code: "lancer", label: 'Lancer', path: 'system.carac.lancer.value' }, - 'derobee': { code: "derobee", label: 'Dérobée', path: 'system.carac.derobee.value' }, - 'chance-actuelle': { code: "chance-actuelle", label: 'Chance actuelle', path: 'system.carac.lancer.value' }, - 'reve-actuel': { code: "reve-actuel", label: 'Rêve actuel', path: 'system.reve.reve.value' }, + [CARACS.MELEE]: { code: CARACS.MELEE, label: 'Mêlée', path: 'system.carac.melee.value' }, + [CARACS.TIR]: { code: CARACS.TIR, label: 'Tir', path: 'system.carac.tir.value' }, + [CARACS.LANCER]: { code: CARACS.LANCER, label: 'Lancer', path: 'system.carac.lancer.value' }, + [CARACS.DEROBEE]: { code: CARACS.DEROBEE, label: 'Dérobée', path: 'system.carac.derobee.value' }, + [CARACS.CHANCE_ACTUELLE]: { code: CARACS.CHANCE_ACTUELLE, label: 'Chance actuelle', path: 'system.carac.lancer.value' }, + [CARACS.REVE_ACTUEL]: { code: CARACS.REVE_ACTUEL, label: 'Rêve actuel', path: 'system.reve.reve.value' }, } export const LIST_CARAC_ROLL = Object.values(LIST_CARAC_PERSONNAGE).filter(it => it.isCarac && it.code != 'taille') @@ -125,11 +134,11 @@ export class RdDCarac { } static isIntellect(caracLabel) { - return Grammar.toLowerCaseNoAccent(caracLabel) == 'intellect'; + return Grammar.toLowerCaseNoAccent(caracLabel) == CARACS.INTELLECT } static isVolonte(caracLabel) { - return Grammar.toLowerCaseNoAccent(caracLabel) == 'volonte'; + return Grammar.toLowerCaseNoAccent(caracLabel) == CARACS.VOLONTE } static isChance(caracLabel) { return Grammar.toLowerCaseNoAccent(caracLabel)?.match(/chance(( |-)?actuelle)?/); diff --git a/module/rdd-combat.js b/module/rdd-combat.js index 1a55c752..2f858307 100644 --- a/module/rdd-combat.js +++ b/module/rdd-combat.js @@ -15,6 +15,10 @@ import { RdDItemArme } from "./item/arme.js"; import { RdDItemCompetence } from "./item-competence.js"; import { RdDItemCompetenceCreature } from "./item-competencecreature.js"; import { RdDInitiative } from "./initiative.mjs"; +import RollDialog from "./roll/roll-dialog.mjs"; +import { PART_DEFENSE } from "./roll/roll-part-defense.mjs"; +import { PART_ATTAQUE } from "./roll/roll-part-attaque.mjs"; +import { RollDialogAdapter } from "./roll/roll-dialog-adapter.mjs"; /* -------------------------------------------- */ const premierRoundInit = [ @@ -398,6 +402,7 @@ export class RdDCombat { /* -------------------------------------------- */ static registerChatCallbacks(html) { for (let button of [ + '.defense-button', '.parer-button', '.esquiver-button', '.particuliere-attaque', @@ -466,6 +471,8 @@ export class RdDCombat { switch (button) { case '.particuliere-attaque': return await this.choixParticuliere(attackerRoll, event.currentTarget.attributes['data-mode'].value); + case '.defense-button': return this.defenseV2(attackerRoll); + case '.parer-button': return this.parade(attackerRoll, armeParadeId); case '.esquiver-button': return this.esquive(attackerRoll, compId, competence); case '.encaisser-button': return this.encaisser(attackerRoll, defenderRoll); @@ -713,9 +720,6 @@ export class RdDCombat { if (RdDCombat.isReussite(attackerRoll)) { return await this._onAttaqueNormale(attackerRoll) } - // if (RdDCombat.isParticuliere(attackerRoll) && attackerRoll.particuliere == undefined) { - // return - // } if (RdDCombat.isEchecTotal(attackerRoll)) { return await this._onAttaqueEchecTotal(attackerRoll) } @@ -857,7 +861,7 @@ export class RdDCombat { /* -------------------------------------------- */ _filterArmesParade(defender, competence, armeAttaque) { - let defenses = defender.items.filter(it => RdDItemArme.isParade(it)) + let defenses = defender.items.filter(it => it.isParade()) defenses = foundry.utils.duplicate(defenses) defenses.forEach(armeDefense => { // Ajout du # d'utilisation ce round @@ -946,6 +950,41 @@ export class RdDCombat { dialog.render(true); } + async defenseV2(attackerRoll) { + + // this._prepareParade(attackerRoll, arme, competence); + const rollData = + { + ids: { + actorId: this.defender.id, + actorTokenId: this.defenderTokenId, + opponentTokenId: this.attackerTokenId, + opponentId: this.attackerId, + }, + mode: { + allowed: ['defense'], + current: 'defense' + }, + attaque: RollDialogAdapter.mapActionAttaque(attackerRoll), + passeArme: attackerRoll.passeArme, + } + + await RollDialog.create(rollData, { + onRoll: (dialog) => { + this._onCloseRollDialog(), + dialog.close() + }, + customChatMessage: true, + callbacks: [async (actor, rd) => { + this.removeChatMessageActionsPasseArme(rd.passeArme) + // defense: esquive / arme de parade / competence de défense + await rd.active.actor.incDecItemUse(rd.current[PART_DEFENSE].defense?.id, !RdDCombat.isParticuliere(rd)) + await this._onDefenseV2(rd) + }] + }) + } + + /* -------------------------------------------- */ _prepareParade(attackerRoll, armeParade, competenceParade) { let defenderRoll = { @@ -971,7 +1010,6 @@ export class RdDCombat { return defenderRoll; } - async _onParade(defenderRoll) { if (RdDCombat.isReussite(defenderRoll)) { await this._onParadeNormale(defenderRoll) @@ -982,6 +1020,16 @@ export class RdDCombat { } await this._onParadeEchec(defenderRoll) } + async _onDefenseV2(defenderRoll) { + if (RdDCombat.isReussite(defenderRoll)) { + await this._onParadeNormale(defenderRoll) + if (RdDCombat.isParticuliere(defenderRoll)) { + await this._onParadeParticuliere(defenderRoll) + } + return + } + await this._onParadeEchec(defenderRoll) + } /* -------------------------------------------- */ async _onParadeParticuliere(defenderRoll) { @@ -1255,4 +1303,8 @@ export class RdDCombat { alias: alias }) } -} \ No newline at end of file +} + +function newFunction(attackerRoll) { + return attackerRoll.diffLibre; +} diff --git a/module/rdd-empoignade.js b/module/rdd-empoignade.js index 3b532d74..f7fce4a0 100644 --- a/module/rdd-empoignade.js +++ b/module/rdd-empoignade.js @@ -1,10 +1,9 @@ -/* -------------------------------------------- */ -import { RdDRoll } from "./rdd-roll.js"; -import { RdDItemCompetenceCreature } from "./item-competencecreature.js"; -import { ChatUtility } from "./chat-utility.js"; import { STATUSES } from "./settings/status-effects.js"; import { ITEM_TYPES } from "./constants.js"; +import { ChatUtility } from "./chat-utility.js"; import { RdDRollResult } from "./rdd-roll-result.js"; +import { RdDRoll } from "./rdd-roll.js"; +import { MappingCreatureArme } from "./item/mapping-creature-arme.mjs"; /* -------------------------------------------- */ export class RdDEmpoignade { @@ -186,7 +185,7 @@ export class RdDEmpoignade { malusTaille: RdDEmpoignade.getMalusTaille(empoignade, attacker, defender) } if (attacker.isCreatureEntite()) { - RdDItemCompetenceCreature.setRollDataCreature(rollData) + MappingCreatureArme.setRollDataCreature(rollData) } if (empoignade.system.pointsemp >= 2) { if (!empoignade.system.ausol) { diff --git a/module/rdd-hotbar-drop.js b/module/rdd-hotbar-drop.js index 35e15415..84e004c6 100644 --- a/module/rdd-hotbar-drop.js +++ b/module/rdd-hotbar-drop.js @@ -1,5 +1,4 @@ -import { RdDItemArme } from "./item/arme.js"; -import { RdDItemCompetenceCreature } from "./item-competencecreature.js"; +import { ATTAQUE_TYPE, RdDItemArme } from "./item/arme.js"; import { ITEM_TYPES } from "./constants.js"; export class RdDHotbar { @@ -20,10 +19,13 @@ export class RdDHotbar { await game.user.assignHotbarMacro(macro, slot); } - static $macroNameSuffix(armeCompetence) { - switch (armeCompetence) { - case '(1 main)': return ' (1 main)'; - case '(2 mains)': return ' (2 main)'; + static $macroNameSuffix(maniement) { + switch (maniement) { + case ATTAQUE_TYPE.UNE_MAIN: + case ATTAQUE_TYPE.DEUX_MAINS: + case ATTAQUE_TYPE.LANCER: + case ATTAQUE_TYPE.TIR: + return ' ' + maniement case 'tir': return ' (tir)'; case 'lancer': return ' (lancer)'; case 'pugilat': return ' (pugilat)'; @@ -39,22 +41,22 @@ export class RdDHotbar { // Les armes peuvent avoir plusieurs usages if (item.system.competence != '') { if (item.system.unemain) { - await this.createItemMacro(item, slot++, '(1 main)') + await this.createItemMacro(item, slot++, ATTAQUE_TYPE.UNE_MAIN) } if (item.system.deuxmains) { - await this.createItemMacro(item, slot++, '(2 mains)') + await this.createItemMacro(item, slot++, ATTAQUE_TYPE.DEUX_MAINS) } } if (item.system.lancer != '') { - await this.createItemMacro(item, slot++, 'lancer') + await this.createItemMacro(item, slot++, ATTAQUE_TYPE.LANCER) } if (item.system.tir != '') { - await this.createItemMacro(item, slot++, 'lancer') + await this.createItemMacro(item, slot++, ATTAQUE_TYPE.TIR) } } return case ITEM_TYPES.competencecreature: - const categorie = RdDItemCompetenceCreature.getCategorieAttaque(item) ?? 'competence'; + const categorie = item.getCategorieAttaque() ?? 'competence'; await this.createItemMacro(item, slot, categorie) return default: @@ -127,7 +129,7 @@ export class RdDHotbar { } return actor.rollCompetence(item); case ITEM_TYPES.competencecreature: - return item.system.iscombat && !item.system.isparade + return item.system.iscombat ? actor.rollArme(item, categorieArme) : actor.rollCompetence(item); diff --git a/module/rdd-possession.js b/module/rdd-possession.js index 7ee0921c..1588a917 100644 --- a/module/rdd-possession.js +++ b/module/rdd-possession.js @@ -1,9 +1,7 @@ import { RdDRoll } from "./rdd-roll.js"; -import { RdDItemCompetenceCreature } from "./item-competencecreature.js"; import { Targets } from "./targets.js"; import { ITEM_TYPES } from "./constants.js"; import { RdDRollResult } from "./rdd-roll-result.js"; -import { Grammar } from "./grammar.js"; /* -------------------------------------------- */ /* On part du principe qu'une entité démarre tjs diff --git a/module/rdd-utility.js b/module/rdd-utility.js index 2347bc4e..69b802b5 100644 --- a/module/rdd-utility.js +++ b/module/rdd-utility.js @@ -19,7 +19,7 @@ import { RdDEmpoignade } from "./rdd-empoignade.js"; import { ExperienceLog } from "./actor/experience-log.js"; import { RdDCoeur } from "./coeur/rdd-coeur.js"; import { APP_ASTROLOGIE_REFRESH } from "./sommeil/app-astrologie.js"; -import { ITEM_TYPES, RDD_CONFIG } from "./constants.js"; +import { ITEM_TYPES, RDD_CONFIG, SYSTEM_RDD } from "./constants.js"; import { RdDBaseActor } from "./actor/base-actor.js"; import { RdDCarac } from "./rdd-carac.js"; import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js"; @@ -271,6 +271,7 @@ export class RdDUtility { // foundry et options Handlebars.registerHelper('RDD_CONFIG', path => RDD_CONFIG[path]) + Handlebars.registerHelper('settings-get', (setting) => game.settings.get(SYSTEM_RDD, setting)) Handlebars.registerHelper('linkCompendium', (pack, id, name) => RdDUtility.linkCompendium(pack, id, name)); Handlebars.registerHelper('regle-optionnelle', (option) => ReglesOptionnelles.isUsing(option)); @@ -344,7 +345,7 @@ export class RdDUtility { Handlebars.registerHelper('rarete-getChamp', (rarete, field) => RdDRaretes.getChamp(rarete, field)); Handlebars.registerHelper('item-action-applies', (action, item, options) => ItemAction.applies(action, item, options)) Handlebars.registerHelper('item-action-icon', (action, item) => ItemAction.icon(action, item)) - Handlebars.registerHelper('item-name', (item) => item.nameDisplay) + Handlebars.registerHelper('item-name', (item) => item.nameDisplay) // TMRs Handlebars.registerHelper('caseTmr-label', coord => TMRUtility.getTMRLabel(coord)); diff --git a/module/roll/roll-dialog-adapter.mjs b/module/roll/roll-dialog-adapter.mjs index 6897e836..55cadde3 100644 --- a/module/roll/roll-dialog-adapter.mjs +++ b/module/roll/roll-dialog-adapter.mjs @@ -4,6 +4,8 @@ import { PART_COMP } from "./roll-part-comp.mjs"; import { RdDResolutionTable } from "../rdd-resolution-table.js"; import { ReglesOptionnelles } from "../settings/regles-optionnelles.js"; import { PART_OEUVRE } from "./roll-part-oeuvre.mjs"; +import { ATTAQUE_TYPE, RdDItemArme } from "../item/arme.js"; +import { RdDBonus } from "../rdd-bonus.js"; /* -------------------------------------------- */ export class RollDialogAdapter { @@ -87,4 +89,29 @@ export class RollDialogAdapter { rollData.show.title = rollTitle } + static mapActionAttaque(attackerRoll) { + if (attackerRoll.ids) { + return attackerRoll.current[PART_ATTAQUE] + } + const label = attackerRoll.alias + ' ' + attackerRoll.arme.name; + return { + // correspond à l'attaque de RollPartAttaque (dans rollDta.current.attaque) + label: label, + attaque: { + // correspond aux actions d'attaques dans RdDActor.listActionsAttaque + name: label, + // action: 'attaque', + arme: attackerRoll.arme, + comp: attackerRoll.competence, + main: RdDItemArme.getMainAttaque(attackerRoll.competence), + equipe: attackerRoll.arme.system.equipe, + // carac: { key: caracCode, value: caracValue }, + // dommagesArme: dommagesArme, + }, + diff: attackerRoll.diffLibre, + particuliere: attackerRoll.particuliere, + tactique: RdDBonus.find(attackerRoll.tactique), + dmg: attackerRoll.dmg, + } + } } diff --git a/module/roll/roll-dialog.mjs b/module/roll/roll-dialog.mjs index f939aa5e..73522b3c 100644 --- a/module/roll/roll-dialog.mjs +++ b/module/roll/roll-dialog.mjs @@ -187,7 +187,12 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 foundry.applications.handlebars.loadTemplates(ROLL_PARTS.map(p => p.template)) ROLL_PARTS.forEach(p => p.onReady()) - Handlebars.registerHelper('roll-centered-array', (base, show) => RollDialog.centeredArray(base, show)) + Handlebars.registerHelper('roll-centered-array', (base, show) => { + show = Math.abs(show) + const start = base - show + return [...Array(2 * show + 1).keys()].map(it => start + it) + }) + Handlebars.registerHelper('roll-list-item-value', (list, key, path = undefined) => { const selected = list.find(p => p.key == key) if (selected && path && path != '') { @@ -195,6 +200,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 } return selected }) + Handlebars.registerHelper('roll-part-context', (rollData, code) => { const rollPart = ROLL_PARTS.find(it => it.code == code) if (rollPart == undefined) { @@ -211,12 +217,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 }) } - static centeredArray(base, show) { - show = Math.abs(show) - const start = base - show - return [...Array(2 * show + 1).keys()].map(it => start + it) - } - + static async create(rollData, rollOptions = {}) { const rollDialog = new RollDialog(rollData, rollOptions) rollDialog.render(true) @@ -267,30 +268,33 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 /** pre-configure les paramètres des différentes parties de la fenêtre (par exemple, prépare les listes de caractéristiques/compétences */ $loadParts() { const rollData = this.rollData; - const loadedMode = rollData.mode?.current rollData.current = rollData.current ?? {} rollData.selected = rollData.selected ?? {} rollData.mode = rollData.mode ?? {} rollData.mode.retry = rollData.mode.retry ?? false BASIC_PARTS.restore(rollData) + const loadedMode = ROLL_MODE_TABS.find(m => m.code == rollData.mode?.current)?.code + const allowedModes = ROLL_MODE_TABS.filter(m => m.isAllowed(rollData) && m.visible(rollData)).map(m => m.code) + rollData.mode.allowed = rollData.mode.retry ? [loadedMode] : rollData.mode.allowed ?? ROLL_MODE_TABS.map(m => m.code) - rollData.mode.current = loadedMode ?? ROLL_MODE_TABS.find(m => m.isAllowed(rollData) && m.visible(rollData))?.code ?? ROLL_MODE_COMP + rollData.mode.current = allowedModes.find(m => m == rollData.mode?.current) ?? (allowedModes.length > 0 ? allowedModes[0] : ROLL_MODE_COMP) + this.getSelectedMode().setRollDataMode(rollData) - + rollData.refs = this.$prepareRefs(rollData) rollData.options = rollData.options ?? { showDice: true, rollMode: game.settings.get("core", "rollMode") } - + ROLL_PARTS.forEach(p => p.initialize(rollData)) ROLL_PARTS.forEach(p => p.restore(rollData)) ROLL_PARTS.filter(p => p.isValid(rollData)) - .forEach(p => { - p.loadRefs(rollData) - p.prepareContext(rollData) - }) + .forEach(p => { + p.loadRefs(rollData) + p.prepareContext(rollData) + }) this.selectMode(); } - + selectMode() { this.rollData.mode.label = this.getSelectedMode().title(this.rollData) this.getSelectedMode().setRollDataMode(this.rollData) @@ -360,7 +364,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 this.setModeTitle() const visibleRollParts = this.getActiveParts() - visibleRollParts.forEach(p => p.setExternalFilter(visibleRollParts, rollData)) + visibleRollParts.forEach(p => p.applyExternalImpacts(visibleRollParts, rollData)) this.setSpecialComp(visibleRollParts); diff --git a/module/roll/roll-mode-defense.mjs b/module/roll/roll-mode-defense.mjs index 526c5659..13576b3f 100644 --- a/module/roll/roll-mode-defense.mjs +++ b/module/roll/roll-mode-defense.mjs @@ -5,7 +5,7 @@ export class RollModeDefense extends RollMode { get code() { return ROLL_MODE_DEFENSE } get name() { return `Se défendre` } - title(rollData) { return `se défend${rollData.attacker ? ' de' : ''}` } + title(rollData) { return `se défend${rollData.opponent ? ' de' : ''}` } getOpponent(rollData) { return rollData.attacker diff --git a/module/roll/roll-part-appelmoral.mjs b/module/roll/roll-part-appelmoral.mjs index 25a633db..12d4a0bd 100644 --- a/module/roll/roll-part-appelmoral.mjs +++ b/module/roll/roll-part-appelmoral.mjs @@ -37,6 +37,7 @@ export class RollPartAppelMoral extends RollPartCheckbox { } return '' } + getCheckboxLabel(rollData) { return "Appel au moral" } getCheckboxValue(rollData) { return 1 } } diff --git a/module/roll/roll-part-attaque.mjs b/module/roll/roll-part-attaque.mjs index db627c7f..6b69abc9 100644 --- a/module/roll/roll-part-attaque.mjs +++ b/module/roll/roll-part-attaque.mjs @@ -1,12 +1,16 @@ -import { Grammar } from "../grammar.js" +import { RdDBonus } from "../rdd-bonus.js" +import { StatusEffects } from "../settings/status-effects.js" import { ROLL_MODE_ATTAQUE } from "./roll-constants.mjs" import { PART_CARAC } from "./roll-part-carac.mjs" import { PART_COMP } from "./roll-part-comp.mjs" import { RollPartSelect } from "./roll-part-select.mjs" -import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs" +import { PART_SIGN } from "./roll-part-sign.mjs" +import { ROLLDIALOG_SECTION } from "./roll-part.mjs" export const PART_ATTAQUE = 'attaque' +const TACTIQUES = RdDBonus.tactiques.filter(it => it.isTactique) + export class RollPartAttaque extends RollPartSelect { get code() { return PART_ATTAQUE } @@ -18,29 +22,71 @@ export class RollPartAttaque extends RollPartSelect { const refs = this.getRefs(rollData) const attaques = rollData.active.actor.listAttaques() refs.attaques = attaques.map(it => RollPartAttaque.$extractAttaque(it, rollData.active.actor)) - if (refs.attaques.length>0){ + refs.tactiques = TACTIQUES + if (refs.attaques.length > 0) { this.$selectAttaque(rollData) } } choices(refs) { return refs.attaques } - static $extractAttaque(action, actor) { + static $extractAttaque(attaque, actor) { return { - key: `${action.action}::${action.arme.id}::${action.comp.id}`, - label: action.name, - action: action, - arme: action.arme, - comp: action.comp, + key: `${attaque.action}::${attaque.name}`, + label: attaque.name, + attaque: attaque, + tactique: TACTIQUES[0], } } + prepareContext(rollData) { + const current = this.getCurrent(rollData) + current.defenseur = StatusEffects.getActorEffetSurprise(rollData.opponent?.actor, 0) + current.attaquant = StatusEffects.getActorEffetSurprise(rollData.active.actor, current.attaque.forceRequise) + current.dmg = this.$dmgRollV2(rollData, current) + } + + $dmgRollV2(rollData, current) { + const actor = rollData.active.actor + const defender = rollData.opponent?.actor + const dmgArme = RdDBonus.dmgArme(current.attaque.arme, current.attaque.dommagesArme) + const dmg = { + total: 0, + dmgArme: dmgArme, + penetration: current.attaque.arme.penetration(), + dmgTactique: current.tactique?.dmg ?? 0, + dmgParticuliere: 0, // TODO RdDBonus._dmgParticuliere(rollData), + dmgSurprise: current.surpriseDefenseur?.dmg ?? 0, + mortalite: RdDBonus.mortalite(current.dmg?.mortalite, current.attaque.arme.system.mortalite, defender?.isEntite()), + dmgActor: RdDBonus.bonusDmg(actor, current.attaque.carac.key, dmgArme, current.attaque.forceRequise), + dmgForceInsuffisante: Math.min(0, actor.getForce() - current.attaque.forceRequise) + } + dmg.total = dmg.dmgSurprise + dmg.dmgTactique + dmg.dmgArme + dmg.dmgActor + dmg.dmgParticuliere + dmg.dmgForceInsuffisante + return dmg + } + + getAjustements(rollData) { + const current = this.getCurrent(rollData) + const ajustements = [] + if (current.tactique) { + ajustements.push({ label: current.tactique.label, diff: current.tactique.attaque }) + } + if (current.surpriseDefenseur) { + ajustements.push({ label: current.surpriseDefenseur.label, diff: current.surpriseDefenseur.attaque }) + } + return ajustements + } + + $selectAttaque(rollData, key) { - this.selectByKey(rollData, key, 0) + this.selectByKey(rollData, key) } async _onRender(rollDialog, context, options) { const selectAttaque = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-attaque"]`) + const selectTactique = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-tactique"]`) + const checkMortalite = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="check-mortalite"]`) + const current = this.getCurrent(rollDialog.rollData) selectAttaque.addEventListener("change", e => { const selectOptions = e.currentTarget.options @@ -49,18 +95,29 @@ export class RollPartAttaque extends RollPartSelect { rollDialog.setModeTitle() rollDialog.render() }) + + selectTactique.addEventListener("change", e => { + const selectOptions = e.currentTarget.options + const index = selectOptions.selectedIndex + current.tactique = RdDBonus.find(selectOptions[index]?.value) + rollDialog.render() + }) + + checkMortalite?.addEventListener("change", e => { + current.dmg.mortalite = (e.currentTarget.checked ? 'mortel' : 'non-mortel') + rollDialog.render() + }) } - getExternalPartsFilter(partCode, rollData) { + impactOtherPart(part, rollData) { if (this.visible(rollData)) { const current = this.getCurrent(rollData) - switch (partCode) { - case PART_CARAC: return p => Grammar.equalsInsensitive(current.action.carac.key, p.key) - case PART_COMP: return p => p.label == current.comp?.name + switch (part.code) { + case PART_CARAC: return part.filterCaracs(rollData, [current.attaque.carac.key]) + case PART_COMP: return part.filterComps(rollData, [current.attaque.comp?.name]) + case PART_SIGN: return part.setArme(rollData, current.attaque.forceRequise, false) } } return undefined } - - } diff --git a/module/roll/roll-part-carac.mjs b/module/roll/roll-part-carac.mjs index 09171d32..f172d8ce 100644 --- a/module/roll/roll-part-carac.mjs +++ b/module/roll/roll-part-carac.mjs @@ -36,9 +36,13 @@ export class RollPartCarac extends RollPartSelect { } } - setFilter(rollData, filter) { + filterCaracs(rollData, allowed) { + allowed = allowed.filter(it => it != undefined) const refs = this.getRefs(rollData) - refs.caracs = refs.all.filter(filter) + refs.caracs = allowed.length > 0 + // ? refs.all.filter(it => allowed.includes(Grammar.toLowerCaseNoAccent(it.key))) + ? refs.all.filter(it => allowed.includes(it.key)) + : refs.all } prepareContext(rollData) { diff --git a/module/roll/roll-part-checkbox.mjs b/module/roll/roll-part-checkbox.mjs index 1f8ae1e1..1d128941 100644 --- a/module/roll/roll-part-checkbox.mjs +++ b/module/roll/roll-part-checkbox.mjs @@ -18,8 +18,8 @@ export class RollPartCheckbox extends RollPart { } loadRefs(rollData) { - const current = this.getCurrent(rollData) - current.label = this.getCheckboxLabel(rollData) + const refs = this.getRefs(rollData) + refs.label = this.getCheckboxLabel(rollData) } prepareContext(rollData) { @@ -43,7 +43,7 @@ export class RollPartCheckbox extends RollPart { } getCheckboxLabelAjustement(rollData) { - return `${this.getCheckboxIcon(rollData)} ${this.getCurrent(rollData).label}` + return `${this.getCheckboxIcon(rollData)} ${this.getRefs(rollData).label}` } async _onRender(rollDialog, context, options) { diff --git a/module/roll/roll-part-comp.mjs b/module/roll/roll-part-comp.mjs index 78673637..5524599d 100644 --- a/module/roll/roll-part-comp.mjs +++ b/module/roll/roll-part-comp.mjs @@ -45,9 +45,13 @@ export class RollPartComp extends RollPartSelect { } } - setFilter(rollData, filter) { + filterComps(rollData, allowed) { + allowed = allowed.filter(it => it != undefined) const refs = this.getRefs(rollData) - refs.comps = refs.all.filter(filter) + refs.comps = allowed.length > 0 + // ? refs.all.filter(it => allowed.includes(Grammar.toLowerCaseNoAccent(it.label))) + ? refs.all.filter(it => allowed.includes(it.label)) + : refs.all } prepareContext(rollData) { diff --git a/module/roll/roll-part-defense.mjs b/module/roll/roll-part-defense.mjs index b924a815..94c9d164 100644 --- a/module/roll/roll-part-defense.mjs +++ b/module/roll/roll-part-defense.mjs @@ -1,17 +1,133 @@ -import { ROLL_MODE_DEFENSE } from "./roll-constants.mjs" -import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs" +import { ITEM_TYPES } from "../constants.js" +import { Grammar } from "../grammar.js" +import { ATTAQUE_TYPE, RdDItemArme } from "../item/arme.js" +import { RdDBonus } from "../rdd-bonus.js" +import { CARACS } from "../rdd-carac.js" +import { StatusEffects } from "../settings/status-effects.js" +import { DIFF_MODE, ROLL_MODE_DEFENSE } from "./roll-constants.mjs" +import { PART_CARAC } from "./roll-part-carac.mjs" +import { PART_COMP } from "./roll-part-comp.mjs" +import { PART_DIFF } from "./roll-part-diff.mjs" +import { RollPartSelect } from "./roll-part-select.mjs" +import { PART_SIGN } from "./roll-part-sign.mjs" +import { ROLLDIALOG_SECTION } from "./roll-part.mjs" export const PART_DEFENSE = 'defense' -export class RollPartDefense extends RollPart { +export class RollPartDefense extends RollPartSelect { get code() { return PART_DEFENSE } get section() { return ROLLDIALOG_SECTION.CHOIX } visible(rollData) { return this.isRollMode(rollData, ROLL_MODE_DEFENSE) } - loadRefs(rollData) { - const refs = this.getRefs(rollData) - refs.defenses =[] + static getDiffAttaque(attackerRoll) { + // TODO: rollDataV2? + return attackerRoll.diffLibre; } + loadRefs(rollData) { + const refs = this.getRefs(rollData) + const attaque = rollData.attaque + const defenseur = rollData.active.actor + refs.isDistance = [ATTAQUE_TYPE.TIR, ATTAQUE_TYPE.LANCER].find(it => it == attaque?.main) + const esquives = refs.isDistance == ATTAQUE_TYPE.TIR ? [] : defenseur.getCompetencesEsquive() + .map(it => RollPartDefense.$extractEsquive(it, defenseur)) + + const parades = defenseur.items.filter(it => it.isParade() && (!refs.isDistance || it.isBouclier())) + .map(it => RollPartDefense.$extractParade(it, attaque?.attaque.arme, defenseur)) + + refs.defenses = [...esquives, ...parades].filter(it => it != undefined) + this.$selectDefense(rollData) + } + + static $extractEsquive(esquive, defenseur) { + return { + key: esquive.id, + label: esquive.name, + img: esquive.img, + // TODO: carac pour créatures + carac: defenseur.isPersonnage() ? CARACS.DEROBEE : esquive.name, + comp: esquive + } + } + + static $extractParade(armeDefense, armeAttaque, defenseur) { + const comp = (ITEM_TYPES.competencecreature == armeDefense.type) + ? armeDefense + : defenseur.getCompetence(armeDefense.system.competence) + return { + key: armeDefense.id, + label: 'Parade ' + armeDefense.name, + img: armeDefense.img, + // TODO: carac pour créatures + carac: defenseur.isPersonnage() ? CARACS.MELEE : comp.name, + comp: comp, + arme: armeDefense, + forceRequise: armeDefense ? RdDItemArme.valeurMain(armeDefense.system.force ?? 0, RdDItemArme.getMainAttaque(comp)) : 0, + typeParade: armeAttaque ? RdDItemArme.defenseArmeParade(armeDefense, armeAttaque) : 'norm' + } + } + + prepareContext(rollData) { + const current = this.getCurrent(rollData) + current.defenseur = StatusEffects.getActorEffetSurprise(rollData.active.actor, current.forceRequise) + + // current.dmg = this.$dmgRollV2(rollData, current) + } + + getAjustements(rollData) { + return [] + } + + choices(refs) { return refs.defenses } + + $selectDefense(rollData, key) { + this.selectByKey(rollData, key) + } + + async _onRender(rollDialog, context, options) { + const selectDefense = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-defense"]`) + + selectDefense.addEventListener("change", e => { + const selectOptions = e.currentTarget.options + const index = selectOptions.selectedIndex + this.$selectDefense(rollDialog.rollData, selectOptions[index]?.value) + rollDialog.setModeTitle() + rollDialog.render() + }) + } + + impactOtherPart(part, rollData) { + if (this.visible(rollData)) { + const current = this.getCurrent(rollData) + switch (part.code) { + case PART_CARAC: return part.filterCaracs(rollData, [current.carac]) + case PART_COMP: return part.filterComps(rollData, [current.comp?.name]) + case PART_DIFF: return part.setDiff(rollData, this.getDiffDefense(rollData)) + case PART_SIGN: return part.setArme(rollData, current.forceRequise, this.isArmeDisparate(rollData)) + } + } + return undefined + } + + isArmeDisparate(rollData) { + const armeDefense = this.getCurrent(rollData).arme + if (armeDefense) { + const armeAttaque = rollData.attaque?.attaque.arme + return RdDItemArme.defenseArmeParade(armeAttaque, armeDefense) == 'sign' + } + return false + } + + getDiffDefense(rollData) { + const current = this.getCurrent(rollData) + const refs = this.getRefs(rollData) + if (refs.isDistance) { + // Déterminer la difficulté de parade + return { diff: 0, mode: DIFF_MODE.LIBRE } + } + else { + return { diff: rollData.attaque.diff, mode: DIFF_MODE.DEFENSE } + } + } } diff --git a/module/roll/roll-part-diff.mjs b/module/roll/roll-part-diff.mjs index 42ca4c54..437714f7 100644 --- a/module/roll/roll-part-diff.mjs +++ b/module/roll/roll-part-diff.mjs @@ -50,6 +50,12 @@ export class RollPartDiff extends RollPart { ) } + setDiff(rollData, diffDefense) { + const current = this.getCurrent(rollData) + current.value = diffDefense.diff + current.mode = diffDefense.mode + } + getAjustements(rollData) { const current = this.getCurrent(rollData) return [{ @@ -67,4 +73,5 @@ export class RollPartDiff extends RollPart { }) } + } \ No newline at end of file diff --git a/module/roll/roll-part-jeu.mjs b/module/roll/roll-part-jeu.mjs index 5dad73ff..7ab6d654 100644 --- a/module/roll/roll-part-jeu.mjs +++ b/module/roll/roll-part-jeu.mjs @@ -91,12 +91,12 @@ export class RollPartJeu extends RollPartSelect { }) } - getExternalPartsFilter(partCode, rollData) { + impactOtherPart(part, rollData) { if (this.visible(rollData)) { const current = this.getCurrent(rollData) - switch (partCode) { - case PART_CARAC: return p => current.caracs?.includes(Grammar.toLowerCaseNoAccent(p.key)) - case PART_COMP: return p => p.label == current.comp?.name + switch (part.code) { + case PART_CARAC: return part.filterCaracs(rollData, current.caracs) + case PART_COMP: return part.filterComps(rollData,[current.comp?.name]) } } return undefined diff --git a/module/roll/roll-part-meditation.mjs b/module/roll/roll-part-meditation.mjs index 6c765f76..07a6701b 100644 --- a/module/roll/roll-part-meditation.mjs +++ b/module/roll/roll-part-meditation.mjs @@ -1,6 +1,6 @@ import { ITEM_TYPES } from "../constants.js" import { Grammar } from "../grammar.js" -import { RdDCarac } from "../rdd-carac.js" +import { CARACS, RdDCarac } from "../rdd-carac.js" import { RdDTimestamp } from "../time/rdd-timestamp.js" import { TMRUtility } from "../tmr-utility.js" import { ROLL_MODE_MEDITATION } from "./roll-constants.mjs" @@ -104,12 +104,12 @@ export class RollPartMeditation extends RollPartSelect { }) } - getExternalPartsFilter(partCode, rollData) { + impactOtherPart(part, rollData) { if (this.visible(rollData)) { const current = this.getCurrent(rollData) - switch (partCode) { - case PART_CARAC: return p => RdDCarac.isIntellect(p.key) - case PART_COMP: return p => p.label == current.comp?.name + switch (part.code) { + case PART_CARAC: return part.filterCaracs(rollData, [CARACS.INTELLECT]) + case PART_COMP: return part.filterComps(rollData,[current.comp?.name]) } } return undefined diff --git a/module/roll/roll-part-oeuvre.mjs b/module/roll/roll-part-oeuvre.mjs index 97eaa782..f77df9b6 100644 --- a/module/roll/roll-part-oeuvre.mjs +++ b/module/roll/roll-part-oeuvre.mjs @@ -43,15 +43,15 @@ export class RollPartOeuvre extends RollPartSelect { loadRefs(rollData) { const refs = this.getRefs(rollData) refs.oeuvres = rollData.active.actor.items - .filter(it => it.isOeuvre() && RollPartOeuvre.getArt(it)) - .map(it => RollPartOeuvre.$extractOeuvre(it, rollData.active.actor)) + .filter(it => it.isOeuvre() && RollPartOeuvre.getArt(it)) + .map(it => RollPartOeuvre.$extractOeuvre(it, rollData.active.actor)) if (refs.oeuvres.length > 0) { this.$selectOeuvre(rollData) } } - + choices(refs) { return refs.oeuvres } - + static $extractOeuvre(oeuvre, actor) { const art = RollPartOeuvre.getArt(oeuvre) return { @@ -64,7 +64,7 @@ export class RollPartOeuvre extends RollPartSelect { comp: actor.getCompetence(art.competence(oeuvre)) } } - + static getArt(oeuvre) { return ARTS.find(it => it.type == oeuvre.type) } @@ -85,12 +85,12 @@ export class RollPartOeuvre extends RollPartSelect { }) } - getExternalPartsFilter(partCode, rollData) { + impactOtherPart(part, rollData) { if (this.visible(rollData)) { const current = this.getCurrent(rollData) - switch (partCode) { - case PART_CARAC: return p => current.caracs?.includes(Grammar.toLowerCaseNoAccent(p.key)) - case PART_COMP: return p => p.label == current.comp?.name + switch (part.code) { + case PART_CARAC: return part.filterCaracs(rollData, current.caracs) + case PART_COMP: return part.filterComps(rollData,[current.comp?.name]) } } return undefined diff --git a/module/roll/roll-part-select.mjs b/module/roll/roll-part-select.mjs index c8239de3..6427983d 100644 --- a/module/roll/roll-part-select.mjs +++ b/module/roll/roll-part-select.mjs @@ -27,7 +27,7 @@ export class RollPartSelect extends RollPart { const current = this.getCurrent(rollData) const newChoice = (choices.length == 0) ? { key: '', value: defValue } - : this.$getSelectedChoice(choices, key ?? current?.key ?? refs.key ?? '') + : this.$getSelectedChoice(choices, key ?? current?.key ?? refs?.key ?? '') this.setCurrent(rollData, newChoice) return newChoice } diff --git a/module/roll/roll-part-sign.mjs b/module/roll/roll-part-sign.mjs index 588e5bab..4a88fb95 100644 --- a/module/roll/roll-part-sign.mjs +++ b/module/roll/roll-part-sign.mjs @@ -1,4 +1,5 @@ import { Misc } from "../misc.js" +import { ReglesOptionnelles } from "../settings/regles-optionnelles.js" import { StatusEffects } from "../settings/status-effects.js" import { ROLL_MODE_ATTAQUE, ROLL_MODE_DEFENSE } from "./roll-constants.mjs" import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs" @@ -22,11 +23,6 @@ export class RollPartSign extends RollPart { this.setSaved(targetData, this.getCurrent(rollData)) } - // visible(rollData) { - // const current = this.getCurrent(rollData) - // return current.surprise != '' - // } - isCombat(rollData) { return [ROLL_MODE_ATTAQUE, ROLL_MODE_DEFENSE].includes(rollData.mode.current) || rollData.mode.isCombat } @@ -42,41 +38,61 @@ export class RollPartSign extends RollPart { const actor = rollData.active.actor; const isCombat = this.isCombat(rollData) const current = this.getCurrent(rollData) + current.armeDisparate = isCombat && current.armeDisparate + current.forceRequise = current.forceRequise ?? 0 current.surprise = actor.getSurprise(isCombat) current.reasons = actor.getEffects(it => StatusEffects.niveauSurprise(it) > 0).map(it => it.name) current.diviseur = 1 - if (isCombat && actor.isDemiReve()) { - current.reasons.push('Demi-rêve en combat') - } if (current.surprise == 'demi') { current.diviseur *= 2 } - - if (this.isAttaqueFinesse(rollData)) { - current.diviseur *= 2 - current.reasons.push('Attaque en finesse') + if (isCombat && actor.isDemiReve()) { + current.reasons.push('Demi-rêve en combat') } - if (this.isForceInsuffisante(rollData)) { + if (this.isParadeArmeDisparate(current)) { + current.diviseur *= 2 + current.reasons.push('Armes disparates') + } + if (this.isForceInsuffisante(actor, current)) { current.diviseur *= 2 current.reasons.push('Force insuffisante') } + if (this.isAttaqueFinesse(rollData)) { + current.diviseur *= 2 + current.reasons.push('Particulière en finesse') + } + + if (!ReglesOptionnelles.isUsing('tripleSignificative')) { + current.diviseur = Math.min(current.diviseur, 4); + } + current.reason = current.reasons.join(', ') } - isForceInsuffisante(rollData) { - //this.isCombat(rollData) && ... arme avec force min - return this.isCombat(rollData) && true + isAttaqueFinesse(rollData) { + return ROLL_MODE_DEFENSE == rollData.mode.current && rollData.attaque.particuliere == 'finesse' } - isAttaqueFinesse(rollData) { - // this.rollData.selected[PART_DEFENSE] && attaquant avec particulière en finesse - return ROLL_MODE_DEFENSE == rollData.mode.current && true + isForceInsuffisante(actor, current) { + if (actor?.isPersonnage()) { + const requise = current.forceRequise + const force = parseInt(actor.system.carac.force.value) + return requise > force + } + return false + } + + isParadeArmeDisparate(current) { + return current.armeDisparate } getAjustements(rollData) { const current = this.getCurrent(rollData) if (current.surprise == 'demi') { - return [{ label: 'Significative requise ' + Misc.getFractionOneN(current.diviseur), diff: undefined }] + return [ + { label: 'Significative requise ' + Misc.getFractionOneN(current.diviseur), diff: undefined }, + ...current.reasons.map(it => { return { label: ' ' + it, diff: undefined } }) + ] } return [] } @@ -90,4 +106,9 @@ export class RollPartSign extends RollPart { }) } + setArme(rollData, forceRequise, armeDisparate) { + const current = this.getCurrent(rollData) + current.armeDisparate = armeDisparate + current.forceRequise = forceRequise + } } \ No newline at end of file diff --git a/module/roll/roll-part-sort.mjs b/module/roll/roll-part-sort.mjs index 9d014bfa..6434af62 100644 --- a/module/roll/roll-part-sort.mjs +++ b/module/roll/roll-part-sort.mjs @@ -6,6 +6,7 @@ import { ROLLDIALOG_SECTION } from "./roll-part.mjs" import { TMRUtility } from "../tmr-utility.js" import { RdDItemSort } from "../item-sort.js" import { RollPartSelect } from "./roll-part-select.mjs" +import { CARACS } from "../rdd-carac.js" export const PART_SORT = "sort" @@ -115,12 +116,12 @@ export class RollPartSort extends RollPartSelect { }) } - getExternalPartsFilter(partCode, rollData) { + impactOtherPart(part, rollData) { if (this.visible(rollData)) { const current = this.getCurrent(rollData) - switch (partCode) { - case PART_CARAC: return p => p.key == 'reve' - case PART_COMP: return p => current.draconics?.includes(p.label) + switch (part.code) { + case PART_CARAC: return part.filterCaracs(rollData, [CARACS.REVE]) + case PART_COMP: return part.filterComps(rollData,current.draconics ?? []) } } return undefined diff --git a/module/roll/roll-part-tache.mjs b/module/roll/roll-part-tache.mjs index fee4b89e..335de3f0 100644 --- a/module/roll/roll-part-tache.mjs +++ b/module/roll/roll-part-tache.mjs @@ -19,14 +19,14 @@ export class RollPartTache extends RollPartSelect { loadRefs(rollData) { const refs = this.getRefs(rollData) refs.taches = rollData.active.actor.itemTypes[ITEM_TYPES.tache] - .filter(tache => tache.system.points_de_tache_courant < tache.system.points_de_tache) - .map(tache => RollPartTache.$extractTache(tache, rollData.active.actor)) + .filter(tache => tache.system.points_de_tache_courant < tache.system.points_de_tache) + .map(tache => RollPartTache.$extractTache(tache, rollData.active.actor)) if (refs.taches.length > 0) { this.$selectTache(rollData) } } choices(refs) { return refs.taches } - + static $extractTache(tache, actor) { return { key: tache.id, @@ -53,12 +53,12 @@ export class RollPartTache extends RollPartSelect { }) } - getExternalPartsFilter(partCode, rollData) { + impactOtherPart(part, rollData) { if (this.visible(rollData)) { const current = this.getCurrent(rollData) - switch (partCode) { - case PART_CARAC: return p => Grammar.equalsInsensitive(p.key, current?.tache.system.carac) - case PART_COMP: return p => p.label == current?.comp.name + switch (part.code) { + case PART_CARAC: return part.filterCaracs(rollData, [current?.tache.system.carac]) + case PART_COMP: return part.filterComps(rollData, [current.comp?.name]) } } return undefined diff --git a/module/roll/roll-part.mjs b/module/roll/roll-part.mjs index b50a95a5..e3225d37 100644 --- a/module/roll/roll-part.mjs +++ b/module/roll/roll-part.mjs @@ -72,16 +72,14 @@ export class RollPart { prepareContext(rollData) { } /** ---- cross roll-part filtering ---- */ - setFilter(rollData, filter) { } + applyImpact(rollData, filter) { } getSpecialComp(rollData) { return [] } setSpecialComp(comps) { } - getExternalPartsFilter(partCode, rollData) { return undefined } - setExternalFilter(visibleRollParts, rollData) { - const predicate = Misc.and( - visibleRollParts.map(p => p.getExternalPartsFilter(this.code, rollData)).filter(f => f != undefined) - ) - this.setFilter(rollData, predicate); + impactOtherPart(partCode, rollData) { } + + applyExternalImpacts(rollParts, rollData) { + rollParts.forEach(part => part.impactOtherPart(this, rollData)) } toTemplateData() { diff --git a/module/rolldata-ajustements.js b/module/rolldata-ajustements.js index 39e358ad..a84c7264 100644 --- a/module/rolldata-ajustements.js +++ b/module/rolldata-ajustements.js @@ -121,7 +121,7 @@ export const referenceAjustements = { }, tactique: { isUsed: (rollData, actor) => rollData.tactique, - getLabel: (rollData, actor) => RdDBonus.find(rollData.tactique).descr, + getLabel: (rollData, actor) => RdDBonus.find(rollData.tactique).label, getValue: (rollData, actor) => RdDBonus.find(rollData.tactique).attaque, }, finesse: { @@ -130,11 +130,11 @@ export const referenceAjustements = { }, surprise: { isUsed: (rollData, actor) => actor.getSurprise(rollData.passeArme), - getDescr: (rollData, actor) => RdDBonus.find(actor.getSurprise()).descr + getDescr: (rollData, actor) => RdDBonus.find(actor.getSurprise()).label }, attaqueDefenseurSurpris: { isUsed: (rollData, actor) => rollData.surpriseDefenseur, - getLabel: (rollData, actor) => RdDBonus.find(rollData.surpriseDefenseur).descr + (rollData.attackerRoll ? '' : ' défenseur'), + getLabel: (rollData, actor) => RdDBonus.find(rollData.surpriseDefenseur).label + (rollData.attackerRoll ? '' : ' défenseur'), getValue: (rollData, actor) => RdDBonus.find(rollData.surpriseDefenseur).attaque, }, armeParade: { diff --git a/module/settings/options-avancees.js b/module/settings/options-avancees.js index 40676d3c..90d9f37d 100644 --- a/module/settings/options-avancees.js +++ b/module/settings/options-avancees.js @@ -2,7 +2,7 @@ import { SYSTEM_RDD } from "../constants.js" import { Misc } from "../misc.js" export const EXPORT_CSV_SCRIPTARIUM = 'export-csv-scriptarium' -export const ROLL_DIALOG_V2 = 'roll-drialog-v2' +export const ROLL_DIALOG_V2 = 'roll-dialog-v2' const OPTIONS_AVANCEES = [ { group: 'Fenêtres', name: ROLL_DIALOG_V2, descr: "Utiliser les nouvelles fenêtres de jet", default: false }, diff --git a/module/settings/status-effects.js b/module/settings/status-effects.js index 242ef3c8..219ed4c2 100644 --- a/module/settings/status-effects.js +++ b/module/settings/status-effects.js @@ -1,4 +1,6 @@ import { SYSTEM_RDD } from "../constants.js"; +import { Misc } from "../misc.js"; +import { RdDBonus } from "../rdd-bonus.js"; export const STATUSES = { StatusGrappling: 'grappling', @@ -12,9 +14,11 @@ export const STATUSES = { StatusBleeding: 'bleeding', StatusDead: 'dead', StatusDemiReve: 'demi-reve', + StatusForceWeak: 'force insuffisante', } -const demiReveStatusEffect = { rdd: true, id: STATUSES.StatusDemiReve, name: 'EFFECT.StatusDemiReve', img: 'systems/foundryvtt-reve-de-dragon/icons/heures/hd12.svg' }; +const forceWeakStatusEffect = { rdd: true, id: STATUSES.StatusForceWeak, name: 'EFFECT.StatusForceWeak', img: 'systems/foundryvtt-reve-de-dragon/assets/actions/weak.svg' }; +const demiReveStatusEffect = { rdd: true, id: STATUSES.StatusDemiReve, name: 'EFFECT.StatusDemiReve', img: 'systems/foundryvtt-reve-de-dragon/assets/actions/sort.svg' }; const rddStatusEffects = [ { rdd: true, id: STATUSES.StatusGrappling, tint: '#33cc33', name: 'EFFECT.StatusGrappling', img: 'systems/foundryvtt-reve-de-dragon/icons/empoignade.webp' }, { rdd: true, id: STATUSES.StatusGrappled, tint: '#ff9900', name: 'EFFECT.StatusGrappled', img: 'systems/foundryvtt-reve-de-dragon/icons/empoignade.webp' }, @@ -29,15 +33,15 @@ const rddStatusEffects = [ { rdd: true, id: STATUSES.StatusBleeding, name: 'EFFECT.StatusBleeding', img: 'icons/svg/blood.svg' }, { rdd: true, id: STATUSES.StatusDead, name: 'EFFECT.StatusDead', img: 'icons/svg/skull.svg' }, - demiReveStatusEffect + demiReveStatusEffect, + forceWeakStatusEffect ]; -const statusDemiSurprise = new Set([STATUSES.StatusStunned, STATUSES.StatusProne, STATUSES.StatusRestrained]) +const statusDemiSurprise = new Set([STATUSES.StatusStunned, STATUSES.StatusProne, STATUSES.StatusRestrained, STATUSES.StatusForceWeak]) const statusSurpriseTotale = new Set([STATUSES.StatusUnconscious, STATUSES.StatusBlind, STATUSES.StatusComma]) export class StatusEffects extends FormApplication { - static onReady() { const rddEffectIds = rddStatusEffects.map(it => it.id); rddStatusEffects.forEach(it => { @@ -67,6 +71,27 @@ export class StatusEffects extends FormApplication { console.log('statusEffects', CONFIG.statusEffects); } + static isSurprise(effect) { + return StatusEffects.niveauSurprise(effect, true) > 0 + } + + static getSurprise(effects, isCombat = undefined) { + return StatusEffects.typeSurprise( + effects.map(it => StatusEffects.niveauSurprise(it, isCombat)) + .reduce(Misc.sum(), 0) + ) + } + + static getActorEffetSurprise(actor, forceRequise) { + const effets = actor?.getEffects(StatusEffects.isSurprise, forceRequise) ?? [] + return { + effets: effets, + surprise: effets.length > 0 + ? RdDBonus.find(StatusEffects.getSurprise(effets, true)) + : undefined + } + } + static niveauSurprise(effect, isCombat) { if (statusSurpriseTotale.intersects(effect.statuses)) { return 2 diff --git a/templates/actor/header-effects.hbs b/templates/actor/header-effects.hbs index 04c5e4de..32295fc5 100644 --- a/templates/actor/header-effects.hbs +++ b/templates/actor/header-effects.hbs @@ -1,6 +1,6 @@
{{#if effects}} - {{#each effects as |effect key|}} + {{#each effects as |effect|}} diff --git a/templates/chat-demande-defense.hbs b/templates/chat-demande-defense.hbs index 7357e12c..54456596 100644 --- a/templates/chat-demande-defense.hbs +++ b/templates/chat-demande-defense.hbs @@ -22,19 +22,34 @@ {{#if (eq defender.type 'personnage')}} - Faire appel à la chance + Faire appel à la chance
{{/if}} {{#if (and (eq defender.type 'personnage') (gt defender.system.compteurs.destinee.value 0))}} - Utiliser la destinée + Utiliser la destinée
{{/if}} {{/unless}} {{else}} + {{#if (settings-get 'rdd-advanced-roll-dialog-v2')}} + + Se défendre + {{#if (or (eq attaqueCategorie 'tir') (eq attaqueCategorie 'lancer'))}} + (difficulté à déterminer) + {{else}} + à {{diffLibre }} + {{/if}} + +
+ {{/if}} {{#each armes as |arme key|}} - Parer à mains nues à {{diffLibre}}{{#if arme.nbUsage}} (Utilisations : {{arme.nbUsage}}){{/if}} + data-attackerId='{{attackerId}}' data-defenderTokenId='{{defenderToken.id}}' data-attackerTokenId='{{attackerToken.id}}' + data-armeid='{{arme._id}}' data-competence='{{arme.system.competence}}'> + Parer à mains nues à {{diffLibre}}{{#if arme.nbUsage}} (Utilisations : {{arme.nbUsage}}){{/if}}
{{/if}} diff --git a/templates/chat-infojet.hbs b/templates/chat-infojet.hbs index 1e6576f4..f1c14ff5 100644 --- a/templates/chat-infojet.hbs +++ b/templates/chat-infojet.hbs @@ -2,13 +2,13 @@ {{rolled.caracValue}} à {{plusMoins rolled.finalLevel}} - {{#if ajustements}} - {{/if}} - {{log this}} - {{#if rolled.factorHtml}}×{{{rolled.factorHtml}}}{{/if}} + {{log rolled}} + {{#if (and rolled.factorHtml (gt rolled.factorHtml 1))}} + ×{{{rolled.factorHtml}}} + = {{rolled.score}}% + ×{{{rolled.factorHtml}}} + {{else}} = {{rolled.score}}% - {{#if rolled.factorHtml}} - ×{{{rolled.factorHtml}}} {{/if}}
diff --git a/templates/roll/roll-ajustements.hbs b/templates/roll/roll-ajustements.hbs index 9164ceca..34851e01 100644 --- a/templates/roll/roll-ajustements.hbs +++ b/templates/roll/roll-ajustements.hbs @@ -1,6 +1,6 @@
- Ajustements: {{rollData.current.carac.value}} à {{plusMoins rollData.current.totaldiff}} + Jet: {{rollData.current.carac.value}} à {{plusMoins rollData.current.totaldiff}}
{{#each rollData.ajustements as |ajust|}} {{#if ajust}} diff --git a/templates/roll/roll-part-attaque.hbs b/templates/roll/roll-part-attaque.hbs index febd2430..f66b5529 100644 --- a/templates/roll/roll-part-attaque.hbs +++ b/templates/roll/roll-part-attaque.hbs @@ -1,14 +1,56 @@ -{{log 'roll-part-attaque.current' current}} -{{log 'roll-part-attaque.refs' refs}} + + + - {{#if current.attaque}} + {{#if current.attaque.arme}} {{/if}} - + {{selectOptions refs.tactiques selected=current.tactique.key valueAttr="key" labelAttr="label"}} + + {{#if (eq current.attaque.arme.system.mortalite 'empoignade')}} + Empoignade, pas de dommages directs + {{else}} + {{#if (and (ne current.attaque.arme.system.mortalite 'non-mortel') (eq current.dmg.penetration 0))}} + + {{/if}} + + {{/if}} + + {{#if current.attaquant.effets}} + + + Attaquant en {{lowerFirst current.attaquant.surprise.label}}:  + {{#each current.attaquant.effets as |effect|}} + {{localize effect.name}} + + {{/each}} + + + {{/if}} + {{#if current.defenseur.surprise}} + + + Defenseur en {{lowerFirst current.defenseur.surprise.label}}:  + {{#each current.defenseur.effets as |effect|}} + {{localize effect.name}} + + {{/each}} + + + {{/if}} + + + \ No newline at end of file diff --git a/templates/roll/roll-part-checkbox.hbs b/templates/roll/roll-part-checkbox.hbs index 20358772..7c0fea04 100644 --- a/templates/roll/roll-part-checkbox.hbs +++ b/templates/roll/roll-part-checkbox.hbs @@ -1,3 +1,3 @@ {{#if current.icon}}{{{current.icon}}}{{/if}} - + diff --git a/templates/roll/roll-part-defense.hbs b/templates/roll/roll-part-defense.hbs index cdc67615..88b0758c 100644 --- a/templates/roll/roll-part-defense.hbs +++ b/templates/roll/roll-part-defense.hbs @@ -1,12 +1,21 @@ - {{#if current.defense}} - - {{/if}} + - {{selectOptions refs.defenses selected=current.key valueAttr="key" labelAttr="label"}} + {{#if current.defenseur.effets}} + + + Defense en {{lowerFirst current.defenseur.surprise.label}}:  + {{#each current.defenseur.effets as |effect|}} + {{localize effect.name}} + + {{/each}} + + + {{/if}} \ No newline at end of file