diff --git a/assets/actions/arme-brisee.svg b/assets/actions/arme-brisee.svg new file mode 100644 index 00000000..02ad0b85 --- /dev/null +++ b/assets/actions/arme-brisee.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/actions/magique.svg b/assets/actions/magique.svg new file mode 100644 index 00000000..bbce68ca --- /dev/null +++ b/assets/actions/magique.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/ui/resistance.svg b/assets/ui/resistance.svg new file mode 100644 index 00000000..cdcd3768 --- /dev/null +++ b/assets/ui/resistance.svg @@ -0,0 +1,110 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/changelog.md b/changelog.md index 3df1b9f6..67c4db44 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,25 @@ # 13.0 +## 13.0.19 - L'introspection d'Illysis + +- Ajout d'un bouton pour les jets de résistance sous rêve actuel +- Fenêtre de jet v2 + - restrictions au propriétaire du personnage + - ouverture de la fenêtre de jets + - appel à la chance + - appel à la destinée + - fermeture par défaut selon le type de jets: + - jets d'attaque + - jets de défense + - jets imposés par un choix d'action + - lancer de sorts + - jets suite à appel à la chance + - gestion des écailles d'efficacité sur les armes + - permettre de faire une attaque même si l'initiative n'est pas faite + - les messages de défense s'affichent correctement avec plusieurs joueurs + - les particulières en force/rapidité sont correctement affichées dans le tchat + - l'expérience sur jet de résistance est limitée à 1 point + ## 13.0.18 - Le reflet d'Illysis - Mise à jour de la feuille de personnage pdf template (avec police correcte) diff --git a/css/foundryvtt-reve-de-dragon.css b/css/foundryvtt-reve-de-dragon.css index ed6aebc0..02953e4a 100644 --- a/css/foundryvtt-reve-de-dragon.css +++ b/css/foundryvtt-reve-de-dragon.css @@ -593,6 +593,9 @@ select, font-size: 1.2rem; font-weight: bold; } +.system-foundryvtt-reve-de-dragon .roll-dialog roll-action roll-section[name="resistance"] { + align-items: flex-end; +} .system-foundryvtt-reve-de-dragon .roll-dialog roll-action roll-section { display: flex; flex-direction: row; @@ -607,6 +610,12 @@ select, margin: 0 1rem; padding: 0; } +.system-foundryvtt-reve-de-dragon .roll-dialog roll-action roll-section img.flag-resistance { + max-width: 1.5rem; + max-height: 1.5rem; + text-align: right; + filter: invert(0.6); +} .system-foundryvtt-reve-de-dragon .roll-dialog roll-conditions { display: flex; flex-direction: column; diff --git a/less/roll-dialog.less b/less/roll-dialog.less index cb995f33..e05b3d4b 100644 --- a/less/roll-dialog.less +++ b/less/roll-dialog.less @@ -160,6 +160,9 @@ font-size: 1.2rem; font-weight: bold; + roll-section[name="resistance"] { + align-items: flex-end; + } roll-section { display: flex; flex-direction: row; @@ -174,6 +177,12 @@ margin: 0 1rem; padding: 0; } + img.flag-resistance { + max-width: 1.5rem; + max-height: 1.5rem; + text-align: right; + filter: invert(0.6); + } } } diff --git a/module/actor-sheet.js b/module/actor-sheet.js index 80d79326..ae01d989 100644 --- a/module/actor-sheet.js +++ b/module/actor-sheet.js @@ -208,7 +208,8 @@ export class RdDActorSheet extends RdDBaseActorSangSheet { } // Points de reve actuel - this.html.find('.roll-reve-actuel').click(async event => await this.actor.rollCarac(CARACS.REVE_ACTUEL, { resistance: true })) + this.html.find('.roll-reve-actuel').click(async event => await this.actor.rollReveActuel({ resistance: false })) + this.html.find('.button-reve-resistance').click(async event => await this.actor.rollReveActuel({ diff: -8, resistance: true })) this.html.find('.action-empoignade').click(async event => await RdDEmpoignade.onAttaqueEmpoignadeFromItem(RdDSheetUtility.getItem(event, this.actor))) this.html.find('.roll-arme').click(async event => { diff --git a/module/actor.js b/module/actor.js index 42369863..1b3695c6 100644 --- a/module/actor.js +++ b/module/actor.js @@ -52,7 +52,6 @@ import { PART_TACHE } from "./roll/roll-part-tache.mjs"; import { PART_COMP } from "./roll/roll-part-comp.mjs"; import { PART_OEUVRE } from "./roll/roll-part-oeuvre.mjs"; import { PART_CUISINE } from "./roll/roll-part-cuisine.mjs"; -import { PART_SORT } from "./roll/roll-part-sort.mjs"; export const MAINS_DIRECTRICES = ['Droitier', 'Gaucher', 'Ambidextre'] @@ -1637,7 +1636,8 @@ export class RdDActor extends RdDBaseActorSang { return } hideChatMessage = hideChatMessage == 'hide' || (Misc.isRollModeHiddenToPlayer() && !game.user.isGM) - let xpData = await this._appliquerExperience(rollData.rolled, rollData.selectedCarac.label, rollData.competence, rollData.jetResistance); + let xpData = await this._appliquerExperience(rollData.rolled, rollData.selectedCarac.label, rollData.competence, + rollData.v2 ? rollData.type.resistance : rollData.jetResistance); if (xpData.length) { const content = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-actor-gain-xp.hbs`, { actor: this, @@ -1945,8 +1945,7 @@ export class RdDActor extends RdDBaseActorSang { diff: { value: diff ?? 0 } } } - RollDialog.create(rollData, foundry.utils.mergeObject(options, { onRollDone: RollDialog.onRollDoneClose })) - return + return await RollDialog.create(rollData) } RdDEmpoignade.checkEmpoignadeEnCours(this) @@ -1980,8 +1979,7 @@ export class RdDActor extends RdDBaseActorSang { selected: { tache: { key: tache.id, forced: options.forced } }, type: { allowed: [PART_TACHE], current: PART_TACHE } } - RollDialog.create(rollData, options) - return + return await RollDialog.create(rollData) } const compData = this.getCompetence(tache.system.competence) @@ -2040,8 +2038,7 @@ export class RdDActor extends RdDBaseActorSang { selected: { jeu: { key: jeu.id } }, type: { allowed: [ROLL_TYPE_JEU], current: ROLL_TYPE_JEU } } - await RollDialog.create(rollData, { onRollDone: RollDialog.onRollDoneClose }) - return + return await RollDialog.create(rollData) } const listCarac = jeu.system.caraccomp.toLowerCase().split(/[.,:\/-]/).map(it => it.trim()); @@ -2069,8 +2066,7 @@ export class RdDActor extends RdDBaseActorSang { selected: { meditation: { key: id } }, type: { allowed: [ROLL_TYPE_MEDITATION], current: ROLL_TYPE_MEDITATION } } - await RollDialog.create(rollData, { onRollDone: RollDialog.onRollDoneClose }) - return + return await RollDialog.create(rollData) } const competence = foundry.utils.duplicate(this.getCompetence(meditation.system.competence)); @@ -2269,7 +2265,7 @@ export class RdDActor extends RdDBaseActorSang { const xpCompetence = competence ? xp - xpCarac : 0; if (jetResistance) { - const message = `Jet de résistance ${jetResistance}, l'expérience est limitée à 1`; + const message = `Jet de résistance, l'expérience est limitée à 1`; ui.notifications.info(message); console.log(message) // max 1 xp sur jets de résistance @@ -3149,7 +3145,7 @@ export class RdDActor extends RdDBaseActorSang { selected: { oeuvre: { key: oeuvre.id } }, type: { allowed: [PART_OEUVRE], current: PART_OEUVRE, }, } - await RollDialog.create(rollData, { onRollDone: RollDialog.onRollDoneClose }) + return await RollDialog.create(rollData) } /* -------------------------------------------- */ @@ -3254,8 +3250,7 @@ export class RdDActor extends RdDBaseActorSang { cuisine: { key: recette.id } } } - RollDialog.create(rollData, { onRollDone: RollDialog.onRollDoneClose }) - return + return await RollDialog.create(rollData) } const artData = { @@ -3305,8 +3300,7 @@ export class RdDActor extends RdDBaseActorSang { cuisine: { key: item.id } } } - RollDialog.create(rollData, { onRollDone: RollDialog.onRollDoneClose }) - return + return await RollDialog.create(rollData) } if (item.getUtilisationCuisine() == 'brut') { diff --git a/module/actor/base-actor-reve.js b/module/actor/base-actor-reve.js index 6f3da2ab..f8c118d2 100644 --- a/module/actor/base-actor-reve.js +++ b/module/actor/base-actor-reve.js @@ -26,7 +26,7 @@ import { BASE_CORPS_A_CORPS, BASE_ESQUIVE, POSSESSION_SANS_DRACONIC } from "../i import { RollDataAjustements } from "../rolldata-ajustements-v1.js"; import { MappingCreatureArme } from "../item/mapping-creature-arme.mjs"; import RollDialog from "../roll/roll-dialog.mjs"; -import { ATTAQUE_ROLL_TYPES, DEFAULT_ROLL_TYPES, DIFF, ROLL_TYPE_ATTAQUE, ROLL_TYPE_COMP, ROLL_TYPE_JEU, ROLL_TYPE_MEDITATION, ROLL_TYPE_OEUVRE, ROLL_TYPE_TACHE } from "../roll/roll-constants.mjs"; +import { ATTAQUE_ROLL_TYPES, DEFAULT_ROLL_TYPES, DIFF, DIFFS, ROLL_TYPE_ATTAQUE, ROLL_TYPE_COMP, ROLL_TYPE_JEU, ROLL_TYPE_MEDITATION, ROLL_TYPE_OEUVRE, ROLL_TYPE_TACHE } from "../roll/roll-constants.mjs"; import { OptionsAvancees, ROLL_DIALOG_V2 } from "../settings/options-avancees.js"; import { PART_COMP } from "../roll/roll-part-comp.mjs"; @@ -284,8 +284,7 @@ export class RdDBaseActorReve extends RdDBaseActor { diff: { value: diff } } } - RollDialog.create(rollData, options) - return + return await RollDialog.create(rollData, options) } const competence = this.getCompetence(compName); @@ -359,6 +358,26 @@ export class RdDBaseActorReve extends RdDBaseActor { }) } /* -------------------------------------------- */ + async rollReveActuel({ diff = 0, resistance = false }) { + if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) { + const rollData = { + ids: { actorId: this.id }, + type: { + allowed: [PART_COMP], + current: PART_COMP, + resistance: resistance + }, + selected: { + carac: { key: CARACS.REVE_ACTUEL, forced: true }, + comp: resistance ? { key: undefined, forced: true } : undefined, + diff: { type: DIFF.DEFAUT, value: diff } + } + } + return await RollDialog.create(rollData) + } + return this.rollCarac(CARACS.REVE_ACTUEL, { diff, resistance }) + } + async rollCarac(caracName, options = {}) { if (Grammar.equalsInsensitive(caracName, CARACS.TAILLE)) { return @@ -366,14 +385,18 @@ export class RdDBaseActorReve extends RdDBaseActor { if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) { const rollData = { ids: { actorId: this.id }, - type: { allowed: DEFAULT_ROLL_TYPES, current: PART_COMP }, + type: { + allowed: options.resistance ? [PART_COMP] : DEFAULT_ROLL_TYPES, + current: PART_COMP, + resistance: options.resistance + }, selected: { carac: { key: caracName }, - comp: options.resistance ? { key: undefined, forced: true } : undefined + comp: options.resistance ? { key: undefined, forced: true } : undefined, + diff: { type: DIFF.DEFAUT, value: options.diff ?? 0 } } } - RollDialog.create(rollData, options) - return + return await RollDialog.create(rollData, options) } foundry.utils.mergeObject(options, { resistance: false, diff: 0 }, { overwrite: false }) @@ -487,7 +510,7 @@ export class RdDBaseActorReve extends RdDBaseActor { allowed: [ROLL_TYPE_ATTAQUE], current: ROLL_TYPE_ATTAQUE } }; - return await RollDialog.create(rollData) + return await RollDialog.create(rollData, { onRollDone: RollDialog.onRollDoneClose }) } }) } diff --git a/module/actor/base-actor.js b/module/actor/base-actor.js index 37c49a23..73f87f8f 100644 --- a/module/actor/base-actor.js +++ b/module/actor/base-actor.js @@ -279,11 +279,22 @@ export class RdDBaseActor extends Actor { async removeEffects(filter = e => true) { if (game.user.isGM) { - const effectsToRemove = this.getEffects(filter); - const ids = effectsToRemove.map(it => it.id); - await this.deleteEmbeddedDocuments('ActiveEffect', ids); + const effectsToRemove = this.getEffects(filter) + if (this.canRemoveEffect(effectsToRemove)) { + const ids = effectsToRemove.map(it => it.id) + await this.deleteEmbeddedDocuments('ActiveEffect', ids) + } } } + canRemoveEffect(effect) { + if (effect.statuses.has(STATUSES.StatusSurEnc)) { + return !this.isSurenc() + } + if (effect.statuses.has(STATUSES.StatusDemiReve)) { + return !this.tmrApp + } + return true + } /* -------------------------------------------- */ async updateCarac(caracName, to) { diff --git a/module/constants.js b/module/constants.js index cf8a91f1..bffd5cb6 100644 --- a/module/constants.js +++ b/module/constants.js @@ -63,6 +63,8 @@ export const RDD_CONFIG = { empoignade: 'systems/foundryvtt-reve-de-dragon/assets/actions/empoignade.svg', forceWeak: 'systems/foundryvtt-reve-de-dragon/assets/actions/weak.svg', surenc: 'systems/foundryvtt-reve-de-dragon/assets/actions/surenc.svg', + magique: 'systems/foundryvtt-reve-de-dragon/assets/actions/magique.svg', + armebrisee: 'systems/foundryvtt-reve-de-dragon/assets/actions/arme-brisee.svg', }, encaissement: { mortel: 'mortel', diff --git a/module/misc.js b/module/misc.js index cca47cfb..6e6808eb 100644 --- a/module/misc.js +++ b/module/misc.js @@ -229,6 +229,14 @@ export class Misc { return undefined } + static async doIfOwner(document, action, orElse = async it => { ui.notifications.warn(`Vous n'avez pas le droit d'agir pour ${it.name}`) }) { + if (Misc.isOwnerPlayer(document)) { + return await action(document) + } else { + return await orElse(document) + } + } + static isOwnerPlayer(document) { return document.testUserPermission && document.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER) } diff --git a/module/rdd-bonus.js b/module/rdd-bonus.js index be0efff0..3541e5b1 100644 --- a/module/rdd-bonus.js +++ b/module/rdd-bonus.js @@ -64,7 +64,7 @@ export class RdDBonus { const dmg = { total: 0, dmgArme: dmgArme, - penetration: arme?.penetration() ?? 0, + penetration: arme?.system.penetration ?? 0, diff: attaque.diff, dmgTactique: attaque.tactique?.dmg ?? 0, dmgParticuliere: RdDBonus._dmgParticuliere(rollData), diff --git a/module/rdd-combat.js b/module/rdd-combat.js index 709b4846..9dde2dd2 100644 --- a/module/rdd-combat.js +++ b/module/rdd-combat.js @@ -315,6 +315,7 @@ export class RdDCombat { switch (sockmsg.msg) { case "msg_encaisser": return RdDCombat.onMsgEncaisser(sockmsg.data); case "msg_defense": return RdDCombat.onMsgDefense(sockmsg.data); + case "msg_defense_v2": return RdDCombat.onMsgDefenseV2(sockmsg.data); } } @@ -367,6 +368,19 @@ export class RdDCombat { return new RdDCombat(attacker, attackerTokenId, defender, defenderTokenId, target) } + static rddCombatForAttackV2(attackerRoll) { + const defenderRoll = RollBasicParts.prepareDefense(attackerRoll) + return RdDCombat.rddCombatForDefenseV2(defenderRoll) + } + + static rddCombatForDefenseV2(defenderRoll) { + let defenderToken = canvas.tokens.get(defenderRoll.active.tokenId) + if (defenderToken) { + return RdDCombat.rddCombatForAttackerAndDefender(defenderRoll.opponent.id, defenderRoll.opponent.tokenId, defenderRoll.active.tokenId) + } + } + + /* -------------------------------------------- */ static onMsgEncaisser(msg) { let defender = canvas.tokens.get(msg.defenderToken.id).actor; @@ -687,7 +701,7 @@ export class RdDCombat { async doRollAttaque(rollData, callbacks = []) { // TODO V2 await this.proposerAjustementTirLancer(rollData) - await RollDialog.create(rollData, { + return await RollDialog.create(rollData, { onRollDone: RollDialog.onRollDoneClose, callbacks: [ async (roll) => await this.onAttaqueV2(roll), @@ -722,9 +736,24 @@ export class RdDCombat { await this._chatMessageDefenseV2(paramChatDefense); } else { - this._socketSendMessageDefense(paramChatDefense, {}); + this._socketSendMessageDefenseV2(paramChatDefense); } } + + _socketSendMessageDefenseV2(paramChatDefense) { + game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_defense_v2", data: {paramChatDefense} }) + } + + static async onMsgDefenseV2(msg) { + if (Misc.isFirstConnectedGM()) { + const paramChatDefense = msg.paramChatDefense + RollBasicParts.restore(paramChatDefense.attackerRoll) + const rddCombat = RdDCombat.rddCombatForAttackV2(paramChatDefense.attackerRoll) + rddCombat?.removeChatMessageActionsPasseArme(paramChatDefense.attackerRoll.passeArme) + await rddCombat?._chatMessageDefenseV2(paramChatDefense) + } + } + async _chatMessageDefenseV2(paramDemandeDefense) { const attackerRoll = paramDemandeDefense.attackerRoll; RollBasicParts.loadSurprises(attackerRoll) @@ -1072,7 +1101,7 @@ export class RdDCombat { } async doRollDefense(rollData, callbacks = []) { - await RollDialog.create(rollData, { + return await RollDialog.create(rollData, { onRollDone: RollDialog.onRollDoneClose, callbacks: [ async (roll) => { diff --git a/module/rdd-empoignade.js b/module/rdd-empoignade.js index 4536dac6..7506fe9a 100644 --- a/module/rdd-empoignade.js +++ b/module/rdd-empoignade.js @@ -17,7 +17,7 @@ export class RdDEmpoignade { /* -------------------------------------------- */ static isCombatantEmpoignade(actorId, tokenId) { const combatant = RdDCombatManager.getCombatant(actorId, tokenId) - return MAP_PHASE.empoignade.rang == combatant?.system.init.rang + return MAP_PHASE.empoignade.rang == combatant?.system.init?.rang } static async ajustementEmpoignade(attacker, defender, adjust = 1) { diff --git a/module/roll/chat-roll-result.mjs b/module/roll/chat-roll-result.mjs index 6a90fb2d..4e892d6b 100644 --- a/module/roll/chat-roll-result.mjs +++ b/module/roll/chat-roll-result.mjs @@ -12,6 +12,7 @@ import { PART_DEFENSE } from "./roll-part-defense.mjs" import { PART_ATTAQUE } from "./roll-part-attaque.mjs" import { RdDRollTables } from "../rdd-rolltables.js" import { RdDEmpoignade } from "../rdd-empoignade.js" +import { Misc } from "../misc.js" export default class ChatRollResult { static init() { @@ -171,13 +172,14 @@ export default class ChatRollResult { } onClickAppelChance(event) { + event.preventDefault() const chatMessage = ChatUtility.getChatMessage(event) const savedRoll = this.loadChatMessageRoll(chatMessage) const actor = game.actors.get(savedRoll.ids.actorId) - actor.rollAppelChance( + Misc.doIfOwner(actor, it => it.rollAppelChance( () => this.onAppelChanceSuccess(savedRoll, chatMessage), () => this.onAppelChanceEchec(savedRoll, chatMessage)) - event.preventDefault() + ) } async onAppelChanceSuccess(savedRoll, chatMessage) { @@ -197,7 +199,7 @@ export default class ChatRollResult { this.getCombat(reRoll)?.doRollAttaque(reRoll, callbacks) break default: { - RollDialog.create(reRoll, { callbacks: callbacks }) + await RollDialog.create(reRoll, { onRollDone: RollDialog.onRollDoneClose, callbacks }) } } } @@ -208,16 +210,18 @@ export default class ChatRollResult { } onClickAppelDestinee(event) { + event.preventDefault() + const chatMessage = ChatUtility.getChatMessage(event) const savedRoll = this.loadChatMessageRoll(chatMessage) const actor = game.actors.get(savedRoll.ids.actorId) - actor.appelDestinee(async () => { + Misc.doIfOwner(actor, it => it.appelDestinee(async () => { const reRoll = foundry.utils.duplicate(savedRoll) reRoll.type.retry = true RdDResolutionTable.significativeRequise(reRoll.rolled) await this.updateChatMessage(chatMessage, reRoll) - }) + })) } async onClickDefense(event) { @@ -235,36 +239,40 @@ export default class ChatRollResult { const savedRoll = this.loadChatMessageRoll(chatMessage) const attaque = savedRoll.attackerRoll const defenderToken = savedRoll.ids.actorTokenId ? canvas.tokens.get(savedRoll.ids.actorTokenId) : undefined - const attackerToken = savedRoll.ids.opponentTokenId ? canvas.tokens.get(savedRoll.ids.opponentTokenId) : undefined - switch (attaque.dmg.mortalite) { - case RDD_CONFIG.encaissement.empoignade: - savedRoll.done = savedRoll.done ?? {} - savedRoll.done.empoignade = await RdDEmpoignade.ajustementEmpoignade(attackerToken.actor, defenderToken.actor) - break - case RDD_CONFIG.encaissement.entiteincarnee: - case RDD_CONFIG.encaissement.nonmortel: - case RDD_CONFIG.encaissement.mortel: - const defender = defenderToken?.actor ?? game.actors.get(savedRoll.ids.actorId) - const attacker = attackerToken?.actor ?? game.actors.get(savedRoll.ids.opponentId) - await defender?.encaisserDommages(attaque.dmg, attacker, undefined, attackerToken, defenderToken) - break - } - if (isMessageDemande) { - ChatUtility.removeChatMessageId(chatMessage.id) - } else { - savedRoll.done.encaissement = true - await this.updateChatMessage(chatMessage, savedRoll) - } + const defender = defenderToken?.actor ?? game.actors.get(savedRoll.ids.actorId) + Misc.doIfOwner(defender, async defender => { + const attackerToken = savedRoll.ids.opponentTokenId ? canvas.tokens.get(savedRoll.ids.opponentTokenId) : undefined + const attacker = attackerToken?.actor ?? game.actors.get(savedRoll.ids.opponentId) + switch (attaque.dmg.mortalite) { + case RDD_CONFIG.encaissement.empoignade: + savedRoll.done = savedRoll.done ?? {} + savedRoll.done.empoignade = await RdDEmpoignade.ajustementEmpoignade(attackerToken.actor, defenderToken.actor) + break + case RDD_CONFIG.encaissement.entiteincarnee: + case RDD_CONFIG.encaissement.nonmortel: + case RDD_CONFIG.encaissement.mortel: + await defender?.encaisserDommages(attaque.dmg, attacker, undefined, attackerToken, defenderToken) + break + } + if (isMessageDemande) { + ChatUtility.removeChatMessageId(chatMessage.id) + } else { + savedRoll.done.encaissement = true + await this.updateChatMessage(chatMessage, savedRoll) + } + }) } async onClickRecul(event) { const chatMessage = ChatUtility.getChatMessage(event) const savedRoll = this.loadChatMessageRoll(chatMessage) + // TODO: gestion sur token non liés? const defender = game.actors.get(savedRoll.ids.actorId) - const attacker = game.actors.get(savedRoll.ids.opponentId) - savedRoll.done.recul = await defender.encaisserRecul(attacker.getForce(), savedRoll.attackerRoll.dmg.dmgArme) - // const reculChoc = this.getReculChoc(savedRoll, defender, attacker) - await this.updateChatMessage(chatMessage, savedRoll) + Misc.doIfOwner(defender, async defender => { + const attacker = game.actors.get(savedRoll.ids.opponentId) + savedRoll.done.recul = await defender.encaisserRecul(attacker.getForce(), savedRoll.attackerRoll.dmg.dmgArme) + await this.updateChatMessage(chatMessage, savedRoll) + }) } async onClickChoixParticuliere(event) { @@ -295,6 +303,7 @@ export default class ChatRollResult { await this.updateChatMessage(chatMessage, savedRoll) } } + async onClickTirerMaladresse(event) { const chatMessage = ChatUtility.getChatMessage(event) const typeMaladresse = event.currentTarget.attributes['data-maladresse'].value @@ -303,4 +312,4 @@ export default class ChatRollResult { savedRoll.type.retry = true await this.updateChatMessage(chatMessage, savedRoll) } -} \ No newline at end of file +} diff --git a/module/roll/roll-dialog-adapter.mjs b/module/roll/roll-dialog-adapter.mjs index dc653679..21c7c0b4 100644 --- a/module/roll/roll-dialog-adapter.mjs +++ b/module/roll/roll-dialog-adapter.mjs @@ -77,7 +77,7 @@ export class RollDialogAdapter { const compKey = rollData.current.comp?.key if (compKey) { rollData.competence = rollData.refs[PART_COMP].all.find(it => it.key == compKey)?.comp - rollData.jetResistance = rollData.type.jetResistance + rollData.jetResistance = rollData.type.resistance } if (rollData.type.current == ROLL_TYPE_OEUVRE) { const oeuvreKey = rollData.current.oeuvre?.key diff --git a/module/roll/roll-dialog.mjs b/module/roll/roll-dialog.mjs index 0797a68a..b179bb9e 100644 --- a/module/roll/roll-dialog.mjs +++ b/module/roll/roll-dialog.mjs @@ -46,6 +46,8 @@ import { OptionsAvancees, ROLL_DIALOG_V2_TEST } from "../settings/options-avance import { ActorImpacts } from "../technical/actor-impacts.mjs"; import { RollPartEmpoignade } from "./roll-part-empoignade.mjs"; import { RollPartEmpoignadeTaille } from "./roll-part-empoignade-taille.mjs"; +import { RollPartEcailles } from "./roll-part-ecailles.mjs"; +import { RollPartResistance } from "./roll-part-resistance.mjs"; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api @@ -68,6 +70,7 @@ const ROLL_PARTS = [ new RollPartActor(), new RollPartAction(), new RollPartOpponent(), + new RollPartResistance(), new RollPartCarac(), new RollPartComp(), @@ -83,6 +86,7 @@ const ROLL_PARTS = [ new RollPartSign(), + new RollPartEcailles(), new RollPartEtat(), new RollPartConditions(), new RollPartEthylisme(), @@ -177,19 +181,25 @@ const ROLL_PARTS = [ /* -------------------------------------------- */ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2) { - static onCloseDoNothing() { - } + static onCloseDoNothing() { } + static onRollDoneDoNothing(dialog, roll) { - dialog.render() - } - static onRollDoneClose(dialog, roll) { - if (roll.type.retry || !OptionsAvancees.isUsing(ROLL_DIALOG_V2_TEST)) + if (roll.type.retry) { dialog.close() + } + else { + dialog.render() + } } - static init() { + static onRollDoneClose(dialog, roll) { + if (roll.type.retry || !OptionsAvancees.isUsing(ROLL_DIALOG_V2_TEST)) { + dialog.close() + } } + static init() { } + static onReady() { foundry.applications.handlebars.loadTemplates({ @@ -239,9 +249,14 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 static async create(rollData, rollOptions = {}) { - const rollDialog = new RollDialog(rollData, rollOptions) - rollDialog.render(true) - return rollDialog + rollData = RollDialog.$prepareRollData(rollData) + return Misc.doIfOwner(rollData.active.actor, + actor => { + const rollDialog = new RollDialog(rollData, rollOptions) + rollDialog.render(true) + return rollDialog + } + ) } static get PARTS() { @@ -321,7 +336,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 super() this.hooks = [] - this.rollData = RollDialog.$prepareRollData(rollData) + this.rollData = rollData this.rollOptions = { callbacks: [ async r => await r.active.actor.appliquerAjoutExperience(r), diff --git a/module/roll/roll-part-attaque.mjs b/module/roll/roll-part-attaque.mjs index 6ca3827a..40cd8924 100644 --- a/module/roll/roll-part-attaque.mjs +++ b/module/roll/roll-part-attaque.mjs @@ -142,7 +142,8 @@ export class RollPartAttaque extends RollPartSelect { comp: { key: 'Dague', forced: true }, diff: { type: DIFF.IMPOSEE, value: -4 } } - }) + }, + { onRollDone: RollDialog.onRollDoneClose }) } impactOtherPart(part, rollData) { diff --git a/module/roll/roll-part-carac.mjs b/module/roll/roll-part-carac.mjs index 55801b36..4b213204 100644 --- a/module/roll/roll-part-carac.mjs +++ b/module/roll/roll-part-carac.mjs @@ -16,11 +16,9 @@ export class RollPartCarac extends RollPartSelect { const selected = this.getSelected(rollData) const actor = rollData.active.actor refs.all = [...this.$getActorCaracs(actor), ...this.$getCaracCompetenceCreature(actor)] - .filter(c => !selected.forced || - (selected.key ? - Grammar.includesLowerCaseNoAccent(c.label, selected.key) - : c.key == '') - ) + if (selected.forced && selected.key) { + refs.all = refs.all.filter(c => c.key == selected.key || Grammar.includesLowerCaseNoAccent(c.label, selected.key)) + } refs.caracs = refs.all this.$selectCarac(rollData) } diff --git a/module/roll/roll-part-ecailles.mjs b/module/roll/roll-part-ecailles.mjs new file mode 100644 index 00000000..af09a27d --- /dev/null +++ b/module/roll/roll-part-ecailles.mjs @@ -0,0 +1,53 @@ +import { RDD_CONFIG } from "../constants.js" +import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs" +import { PART_ATTAQUE } from "./roll-part-attaque.mjs" +import { RollPartCheckbox } from "./roll-part-checkbox.mjs" +import { PART_DEFENSE } from "./roll-part-defense.mjs" + +const ECAILLES = "ecailles" + +export class RollPartEcailles extends RollPartCheckbox { + + get code() { return ECAILLES } + + isValid(rollData) { + return this.isRollType(rollData, ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE) + } + + visible(rollData) { + return this.getEcailles(rollData) != 0 + + } + + getEcailles(rollData) { + const arme = this.getArme(rollData) + return arme?.system.magique ? arme?.system.ecaille_efficacite : 0 + } + + getArme(rollData) { + return this.isRollType(rollData, ROLL_TYPE_ATTAQUE) + ? rollData.current[PART_ATTAQUE]?.arme + : this.isRollType(rollData, ROLL_TYPE_DEFENSE) + ? rollData.current[PART_DEFENSE]?.arme + : undefined + } + + prepareContext(rollData) { + this.loadRefs(rollData) + super.prepareContext(rollData) + } + + getCheckboxIcon(rollData) { + return this.getEcailles(rollData) > 0 + ? `` + : `` + } + + getCheckboxLabel(rollData) { + return this.getEcailles(rollData) > 0 + ? "Efficacité" + : "Défauts" + } + + getCheckboxValue(rollData) { return this.getEcailles(rollData) } +} diff --git a/module/roll/roll-part-empoignade-taille.mjs b/module/roll/roll-part-empoignade-taille.mjs index 92745a71..80779522 100644 --- a/module/roll/roll-part-empoignade-taille.mjs +++ b/module/roll/roll-part-empoignade-taille.mjs @@ -1,8 +1,6 @@ import { RDD_CONFIG } from "../constants.js" -import { ATTAQUE_TYPE_MELEE } from "../item/arme.js" import { RdDEmpoignade } from "../rdd-empoignade.js" import { COMBAT_ROLL_TYPES } from "./roll-constants.mjs" -import { PART_ATTAQUE } from "./roll-part-attaque.mjs" import { RollPartCheckbox } from "./roll-part-checkbox.mjs" const EMPOIGNADE_TAILLE = "empoignade-taille" diff --git a/module/roll/roll-part-resistance.mjs b/module/roll/roll-part-resistance.mjs new file mode 100644 index 00000000..eaf6ffcd --- /dev/null +++ b/module/roll/roll-part-resistance.mjs @@ -0,0 +1,12 @@ +import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs" + +export const PART_RESISTANCE = "resistance" + +export class RollPartResistance extends RollPart { + + get code() { return PART_RESISTANCE } + get section() { return ROLLDIALOG_SECTION.ACTION } + + isValid(rollData) { return rollData.type.resistance == true } + title(rollData) { return "de résistance" } +} diff --git a/module/roll/roll-part.mjs b/module/roll/roll-part.mjs index d54b560f..a76611eb 100644 --- a/module/roll/roll-part.mjs +++ b/module/roll/roll-part.mjs @@ -78,7 +78,7 @@ export class RollPart { * @returns une chaîne vide si rien ne doit être affiché */ title() { return '' } - isRollType(rollData, type) { return rollData.type.current == type } + isRollType(rollData, ...type) { return type.includes(rollData.type.current)} isActive(rollData) { return this.isValid(rollData) && this.visible(rollData) } isValid(rollData) { return true } diff --git a/module/roll/roll-type.mjs b/module/roll/roll-type.mjs index bc21742c..193ae420 100644 --- a/module/roll/roll-type.mjs +++ b/module/roll/roll-type.mjs @@ -23,7 +23,6 @@ export class RollType { setRollDataType(rollData) { rollData.type.opposed = rollData.opponent != undefined - rollData.type.resistance = false /** TODO */ } onSelect(rollData) { diff --git a/templates/actor/header-compteurs.hbs b/templates/actor/header-compteurs.hbs index 8d86aa34..65912cb9 100644 --- a/templates/actor/header-compteurs.hbs +++ b/templates/actor/header-compteurs.hbs @@ -35,6 +35,9 @@
  • diff --git a/templates/chat-demande-defense.hbs b/templates/chat-demande-defense.hbs index 62ae5807..6825a003 100644 --- a/templates/chat-demande-defense.hbs +++ b/templates/chat-demande-defense.hbs @@ -15,8 +15,8 @@ {{~#if (eq active.surprise.key 'demi')}} avec une significative {{/if}} d'une attaque {{~#if attackerRoll.particuliere}} particulière en {{~#if (eq attackerRoll.particuliere 'finesse')}} finesse - {{else if (eq particuliere 'force')}} force - {{else if (eq particuliere 'rapidite')}} rapidité + {{else if (eq attackerRoll.particuliere 'force')}} force + {{else if (eq attackerRoll.particuliere 'rapidite')}} rapidité {{/if~}} {{/if}} de {{opponent.name}} ({{attackerRoll.current.attaque.label}}): diff --git a/templates/roll/roll-part-resistance.hbs b/templates/roll/roll-part-resistance.hbs new file mode 100644 index 00000000..fd448aa4 --- /dev/null +++ b/templates/roll/roll-part-resistance.hbs @@ -0,0 +1,4 @@ +de résistance +