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 @@
+
+
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 @@