diff --git a/changelog.md b/changelog.md
index ad50c309..7cb22398 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,4 +1,12 @@
# 12.0
+## 12.0.18 - A la barbe d'Astrobazzarh
+- Ajout du portrait sur les feuilles simplifiées
+
+## 12.0.16 - Le secret d'Astrobazzarh
+- Fix: les jets envoyés messages uniquement au MJ ne sont plus envoyés à tous les autres joueurs (et dupliqués)
+- Les noms affichés dans les automatisations de combat sont maintenant ceux des tokens plutôt que ceux des acteurs
+- Ajout d'une option pour la localisation des blessures
+
## 12.0.15 - Le messager d'Astrobazzarh
- Correction des faces de dés personalisés dice-so-nice
- Les messages de maladies ne sont plus publics
diff --git a/module/actor-sheet.js b/module/actor-sheet.js
index 5e2ff8b6..8e5ab07c 100644
--- a/module/actor-sheet.js
+++ b/module/actor-sheet.js
@@ -220,18 +220,18 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
// Points de reve actuel
this.html.find('.roll-reve-actuel').click(async event => this.actor.rollCarac('reve-actuel', true))
this.html.find('.empoignade-label a').click(async event => RdDEmpoignade.onAttaqueEmpoignadeFromItem(RdDSheetUtility.getItem(event, this.actor)))
- this.html.find('.roll-arme').click(async event => this.actor.rollArme(foundry.utils.duplicate(this._getEventArmeCombat(event))))
+
+ this.html.find('.roll-arme').click(async event => this.actor.rollArme(foundry.utils.duplicate(this._getEventArmeCombat(event)), 'competence'))
// Initiative pour l'arme
this.html.find('.arme-initiative a').click(async event => {
- let combatant = game.combat.combatants.find(c => c.actor.id == this.actor.id);
+ let combatant = game.combat.combatants.find(c => c.actor.id == this.actor.id)
if (combatant) {
- let action = this._getEventArmeCombat(event);
- RdDCombatManager.rollInitiativeAction(combatant._id, action);
+ RdDCombatManager.rollInitiativeAction(combatant._id, this._getEventArmeCombat(event));
} else {
ui.notifications.info("Impossible de lancer l'initiative sans être dans un combat.");
}
- });
+ })
// Display TMR
this.html.find('.button-tmr').click(async event => this.actor.displayTMR("normal"))
diff --git a/module/actor.js b/module/actor.js
index 73c21990..b8e6cd10 100644
--- a/module/actor.js
+++ b/module/actor.js
@@ -1548,7 +1548,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async appliquerAjoutExperience(rollData, hideChatMessage = 'show') {
- if (!Misc.firstConnectedGM()){
+ if (!Misc.isFirstConnectedGM()){
return
}
hideChatMessage = hideChatMessage == 'hide' || (Misc.isRollModeHiddenToPlayer() && !game.user.isGM)
@@ -3011,7 +3011,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async onCreateOwnedDraconique(item, options, id) {
- if (Misc.isUniqueConnectedGM()) {
+ if (Misc.isFirstConnectedGM()) {
let draconique = Draconique.all().find(it => it.match(item));
if (draconique) {
await draconique.onActorCreateOwned(this, item)
@@ -3023,7 +3023,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async onDeleteOwnedDraconique(item, options, id) {
- if (Misc.isUniqueConnectedGM()) {
+ if (Misc.isFirstConnectedGM()) {
let draconique = Draconique.all().find(it => it.match(item));
if (draconique) {
await draconique.onActorDeleteOwned(this, item)
@@ -3033,7 +3033,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async onDeleteOwnedCaseTmr(item, options, id) {
- if (Misc.isUniqueConnectedGM()) {
+ if (Misc.isFirstConnectedGM()) {
let draconique = Draconique.all().find(it => it.isCase(item));
if (draconique) {
await draconique.onActorDeleteCaseTmr(this, item)
diff --git a/module/actor/base-actor-reve.js b/module/actor/base-actor-reve.js
index 06b560f5..21d2e608 100644
--- a/module/actor/base-actor-reve.js
+++ b/module/actor/base-actor-reve.js
@@ -327,14 +327,15 @@ export class RdDBaseActorReve extends RdDBaseActor {
const competence = this.getCompetence(idOrName);
let rollData = { carac: this.system.carac, competence: competence, arme: options.arme }
if (competence.type == ITEM_TYPES.competencecreature) {
+ const token = RdDUtility.getSelectedToken(this)
const arme = RdDItemCompetenceCreature.armeCreature(competence)
if (arme && options.tryTarget && Targets.hasTargets()) {
- Targets.selectOneToken(target => {
+ Targets.selectOneTargetToken(target => {
if (arme.action == "possession") {
RdDPossession.onAttaquePossession(target, this, competence)
}
else {
- RdDCombat.rddCombatTarget(target, this).attaque(competence, arme)
+ RdDCombat.rddCombatTarget(target, this, token).attaque(competence, arme)
}
});
return;
@@ -364,7 +365,8 @@ export class RdDBaseActorReve extends RdDBaseActor {
* @param {*} categorieArme catégorie d'attaque à utiliser: competence (== melee), lancer, tir; naturelle, possession
* @returns
*/
- rollArme(arme, categorieArme = "competence") {
+ rollArme(arme, categorieArme, token) {
+ token = token ?? RdDUtility.getSelectedToken(this)
const compToUse = this.$getCompetenceArme(arme, categorieArme)
if (!RdDItemArme.isArmeUtilisable(arme)) {
ui.notifications.warn(`Arme inutilisable: ${arme.name} a une résistance de 0 ou moins`)
@@ -385,7 +387,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
return
}
- Targets.selectOneToken(target => {
+ Targets.selectOneTargetToken(target => {
if (Targets.isTargetEntite(target)) {
ui.notifications.warn(`Vous ne pouvez pas attaquer une entité non incarnée avec votre ${arme.name}!!!!`);
return
@@ -395,7 +397,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
if (competence.isCompetencePossession()) {
return RdDPossession.onAttaquePossession(target, this, competence);
}
- RdDCombat.rddCombatTarget(target, this).attaque(competence, arme);
+ RdDCombat.rddCombatTarget(target, this, token).attaque(competence, arme);
})
}
@@ -413,48 +415,47 @@ export class RdDBaseActorReve extends RdDBaseActor {
/* -------------------------------------------- */
async encaisser() { await RdDEncaisser.encaisser(this) }
- async encaisserDommages(rollData, attacker = undefined, show = undefined) {
+ async encaisserDommages(rollData, attacker = undefined, show = undefined, attackerToken = undefined, defenderToken = undefined) {
if (attacker && !await attacker.accorder(this, 'avant-encaissement')) {
return;
}
const armure = await this.computeArmure(rollData);
if (ReglesOptionnelles.isUsing('validation-encaissement-gr')) {
- await this.encaisserDommagesValidationGR(rollData, armure, attacker?.id, show);
+ await this.encaisserDommagesValidationGR(rollData, armure, show, attackerToken, defenderToken);
}
else {
- const jet = await RdDUtility.jetEncaissement(rollData, armure, { showDice: SHOW_DICE });
- await this.$onEncaissement(jet, show, attacker);
+ const jet = await RdDUtility.jetEncaissement(this, rollData, armure, { showDice: SHOW_DICE });
+ await this.$onEncaissement(jet, show, attackerToken, defenderToken)
}
}
- async encaisserDommagesValidationGR(rollData, armure, attackerId, show) {
+ async encaisserDommagesValidationGR(rollData, armure, show, attackerToken, defenderToken) {
if (!game.user.isGM) {
RdDBaseActor.remoteActorCall({
tokenId: this.token?.id,
actorId: this.id,
method: 'encaisserDommagesValidationGR',
- args: [rollData, armure, attackerId, show]
- });
+ args: [rollData, armure, show, attackerToken, defenderToken]
+ })
} else {
- const attacker = game.actors.get(attackerId);
DialogValidationEncaissement.validerEncaissement(this, rollData, armure,
- jet => this.$onEncaissement(jet, show, attacker));
+ jet => this.$onEncaissement(jet, show, attackerToken, defenderToken));
}
}
- async $onEncaissement(jet, show, attacker) {
- await this.onAppliquerJetEncaissement(jet, attacker);
- await this.$afficherEncaissement(jet, show);
+ async $onEncaissement(jet, show, attackerToken, defenderToken) {
+ await this.onAppliquerJetEncaissement(jet, attackerToken);
+ await this.$afficherEncaissement(jet, show, defenderToken);
}
- async onAppliquerJetEncaissement(encaissement, attacker) { }
+ async onAppliquerJetEncaissement(encaissement, attackerToken) { }
- async $afficherEncaissement(encaissement, show) {
+ async $afficherEncaissement(encaissement, show, defenderToken) {
foundry.utils.mergeObject(encaissement, {
- alias: this.name,
+ alias: defenderToken?.name ?? this.name,
hasPlayerOwner: this.hasPlayerOwner,
show: show ?? {}
- });
+ }, {overwrite: false});
await ChatUtility.createChatWithRollMode(
{
diff --git a/module/actor/base-actor-sang.js b/module/actor/base-actor-sang.js
index 978c27c2..48e5299a 100644
--- a/module/actor/base-actor-sang.js
+++ b/module/actor/base-actor-sang.js
@@ -89,9 +89,9 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
/* -------------------------------------------- */
- async onAppliquerJetEncaissement(encaissement, attacker) {
+ async onAppliquerJetEncaissement(encaissement, attackerToken) {
const santeOrig = foundry.utils.duplicate(this.system.sante);
- const blessure = await this.ajouterBlessure(encaissement, attacker); // Will update the result table
+ const blessure = await this.ajouterBlessure(encaissement, attackerToken); // Will update the result table
const perteVie = await this.santeIncDec("vie", -encaissement.vie);
const perteEndurance = await this.santeIncDec("endurance", -encaissement.endurance, blessure?.isCritique());
@@ -169,7 +169,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
/* -------------------------------------------- */
- async ajouterBlessure(encaissement, attacker = undefined) {
+ async ajouterBlessure(encaissement, attackerToken = undefined) {
if (encaissement.gravite < 0) return;
if (encaissement.gravite > 0) {
while (this.countBlessures(it => it.system.gravite == encaissement.gravite) >= RdDItemBlessure.maxBlessures(encaissement.gravite) && encaissement.gravite <= 6) {
@@ -181,7 +181,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
}
}
const endActuelle = this.getEnduranceActuelle();
- const blessure = await RdDItemBlessure.createBlessure(this, encaissement.gravite, encaissement.dmg?.loc.label ?? '', attacker);
+ const blessure = await RdDItemBlessure.createBlessure(this, encaissement.gravite, encaissement.dmg?.loc.label ?? '', attackerToken);
if (blessure.isCritique()) {
encaissement.endurance = endActuelle;
}
diff --git a/module/actor/base-actor.js b/module/actor/base-actor.js
index 57fbcb07..c92b8318 100644
--- a/module/actor/base-actor.js
+++ b/module/actor/base-actor.js
@@ -218,7 +218,7 @@ export class RdDBaseActor extends Actor {
}
async creerObjetParMJ(object) {
- if (!Misc.isUniqueConnectedGM()) {
+ if (!Misc.isFirstConnectedGM()) {
RdDBaseActor.remoteActorCall({
tokenId: this.token?.id,
actorId: this.id,
@@ -335,7 +335,7 @@ export class RdDBaseActor extends Actor {
ui.notifications.info("Inutile de se vendre à soi-même");
return;
}
- if (!Misc.isUniqueConnectedGM()) {
+ if (!Misc.isFirstConnectedGM()) {
RdDBaseActor.remoteActorCall({
actorId: achat.vendeurId ?? achat.acheteurId,
method: 'achatVente',
diff --git a/module/actor/entite.js b/module/actor/entite.js
index 70bc0577..ff0ad06a 100644
--- a/module/actor/entite.js
+++ b/module/actor/entite.js
@@ -74,7 +74,7 @@ export class RdDEntite extends RdDBaseActorReve {
return [STATUSES.StatusComma].includes(effectId);
}
- async onAppliquerJetEncaissement(encaissement, attacker) {
+ async onAppliquerJetEncaissement(encaissement, attackerToken) {
const perteEndurance = await this.santeIncDec("endurance", -encaissement.endurance);
foundry.utils.mergeObject(encaissement, {
resteEndurance: perteEndurance.newValue,
diff --git a/module/actor/export-scriptarium/mapping.js b/module/actor/export-scriptarium/mapping.js
index ffb2b788..6aaee07e 100644
--- a/module/actor/export-scriptarium/mapping.js
+++ b/module/actor/export-scriptarium/mapping.js
@@ -327,7 +327,8 @@ export class Mapping {
const txtByCategories = Object.values(byCategories)
.map(it => it.competencesParNiveau)
.map(byNiveau => {
- const niveaux = Object.keys(byNiveau).map(it => Number(it)).sort(Misc.ascending())
+ const niveaux = Object.keys(byNiveau)
+ .map(it => Number(it)).sort(Misc.ascending())
if (niveaux.length == 0) {
return ''
}
diff --git a/module/chat-utility.js b/module/chat-utility.js
index 76792c86..5f515ce8 100644
--- a/module/chat-utility.js
+++ b/module/chat-utility.js
@@ -49,7 +49,7 @@ export class ChatUtility {
/* -------------------------------------------- */
static onRemoveMessages(socketData) {
- if (Misc.isUniqueConnectedGM()) {
+ if (Misc.isFirstConnectedGM()) {
if (socketData.part) {
const toDelete = game.messages.filter(it => it.content.includes(socketData.part));
toDelete.forEach(it => it.delete());
@@ -63,7 +63,7 @@ export class ChatUtility {
/* -------------------------------------------- */
static removeMessages(socketData) {
- if (Misc.isUniqueConnectedGM()) {
+ if (Misc.isFirstConnectedGM()) {
ChatUtility.onRemoveMessages(socketData);
}
else {
@@ -161,7 +161,7 @@ export class ChatUtility {
/* -------------------------------------------- */
static handleGMChatMessage(socketData) {
console.log("blindMessageToGM", socketData);
- if (Misc.firstConnectedGM()) {
+ if (Misc.isFirstConnectedGM()) {
ChatMessage.create({
user: game.user.id,
whisper: ChatUtility.getGMs(),
diff --git a/module/dialog-validation-encaissement.js b/module/dialog-validation-encaissement.js
index d4c41f61..c0a74d85 100644
--- a/module/dialog-validation-encaissement.js
+++ b/module/dialog-validation-encaissement.js
@@ -8,14 +8,13 @@ import { RdDUtility } from "./rdd-utility.js";
export class DialogValidationEncaissement extends Dialog {
static async validerEncaissement(actor, rollData, armure, onEncaisser) {
- let encaissement = await RdDUtility.jetEncaissement(rollData, armure, { showDice: HIDE_DICE });
+ const encaissement = await RdDUtility.jetEncaissement(actor, rollData, armure, { showDice: HIDE_DICE });
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-validation-encaissement.html', {
actor: actor,
rollData: rollData,
encaissement: encaissement
});
- const dialog = new DialogValidationEncaissement(html, actor, rollData, armure, encaissement, onEncaisser);
- dialog.render(true);
+ new DialogValidationEncaissement(html, actor, rollData, armure, encaissement, onEncaisser).render(true);
}
/* -------------------------------------------- */
@@ -56,14 +55,14 @@ export class DialogValidationEncaissement extends Dialog {
this.html = html;
this.html.find('input.encaissement-roll-result').keyup(async event => {
this.forceDiceResult.total = event.currentTarget.value;
- this.encaissement = await RdDUtility.jetEncaissement(this.rollData, this.armure, { showDice: HIDE_DICE, forceDiceResult: this.forceDiceResult});
+ this.encaissement = await RdDUtility.jetEncaissement(this.actor, this.rollData, this.armure, { showDice: HIDE_DICE, forceDiceResult: this.forceDiceResult});
this.html.find('label.encaissement-total').text(this.encaissement.total);
this.html.find('label.encaissement-blessure').text(this.encaissement.blessures)
});
}
async onValider() {
- this.encaissement = await RdDUtility.jetEncaissement(this.rollData, this.armure, { showDice: SHOW_DICE, forceDiceResult: this.forceDiceResult});
+ this.encaissement = await RdDUtility.jetEncaissement(this.actor, this.rollData, this.armure, { showDice: SHOW_DICE, forceDiceResult: this.forceDiceResult});
this.onEncaisser(this.encaissement)
}
}
diff --git a/module/item-competence.js b/module/item-competence.js
index 25c6659d..f09ca6a8 100644
--- a/module/item-competence.js
+++ b/module/item-competence.js
@@ -190,7 +190,7 @@ export class RdDItemCompetence extends Item {
/* -------------------------------------------- */
static isNiveauBase(item) {
- return Number(item.system.niveau) == RdDItemCompetence.getNiveauBase(item.system.categorie, item.type);
+ return item.system.niveau == undefined || Number(item.system.niveau) == RdDItemCompetence.getNiveauBase(item.system.categorie, item.type);
}
/* -------------------------------------------- */
diff --git a/module/item-sheet.js b/module/item-sheet.js
index 93e3a6c5..dd58ab6f 100644
--- a/module/item-sheet.js
+++ b/module/item-sheet.js
@@ -267,10 +267,17 @@ export class RdDItemSheet extends ItemSheet {
/* -------------------------------------------- */
/** @override */
_updateObject(event, formData) {
- if (this.item.type == 'sort') {
- // Données de bonus de cases ?
- formData['system.bonuscase'] = RdDItemSort.buildBonuscaseFromArrays(formData.bonusValue, formData.caseValue);
+ switch (this.item.type) {
+ case ITEM_TYPES.sort:
+ // Données de bonus de cases ?
+ formData['system.bonuscase'] = RdDItemSort.buildBonuscaseFromArrays(formData.bonusValue, formData.caseValue)
+ break
+ case ITEM_TYPES.competence:
+ if (formData['system.niveau'] == undefined) {
+ formData['system.niveau'] = formData['system.base']
+ }
}
+
return this.item.update(formData);
}
diff --git a/module/misc.js b/module/misc.js
index c22fe21e..a3f5f43d 100644
--- a/module/misc.js
+++ b/module/misc.js
@@ -195,7 +195,7 @@ export class Misc {
return document
}
}
- else if (Misc.isUniqueConnectedGM() || (Misc.connectedGMs().length == 0 && Misc.isOwnerPlayer(document))) {
+ else if (Misc.isFirstConnectedGM() || (Misc.connectedGMs().length == 0 && Misc.isOwnerPlayer(document))) {
return document
}
return undefined
@@ -206,14 +206,14 @@ export class Misc {
}
static isOwnerPlayerOrUniqueConnectedGM(actor) {
- return Misc.isOwnerPlayer(actor) ?? Misc.isUniqueConnectedGM();
+ return Misc.isOwnerPlayer(actor) ?? Misc.isFirstConnectedGM();
}
/**
* @returns true pour un seul utilisateur: le premier GM connecté par ordre d'id
*/
- static isUniqueConnectedGM() {
- return game.user.id == Misc.firstConnectedGMId();
+ static isFirstConnectedGM() {
+ return game.user == Misc.firstConnectedGM();
}
static firstConnectedGMId() {
diff --git a/module/rdd-combat.js b/module/rdd-combat.js
index 68947438..22cca49a 100644
--- a/module/rdd-combat.js
+++ b/module/rdd-combat.js
@@ -53,7 +53,7 @@ export class RdDCombatManager extends Combat {
/* -------------------------------------------- */
async onPreDeleteCombat() {
- if (Misc.isUniqueConnectedGM()) {
+ if (Misc.isFirstConnectedGM()) {
await this.finDeRound({ terminer: true })
ChatUtility.removeChatMessageContaining(`
`)
game.messages.filter(m => ChatUtility.getMessageData(m, 'attacker-roll') != undefined && ChatUtility.getMessageData(m, 'defender-roll') != undefined)
@@ -291,7 +291,7 @@ export class RdDCombatManager extends Combat {
/* -------------------------------------------- */
static processPremierRoundInit() {
// Check if we have the whole init !
- if (Misc.isUniqueConnectedGM() && game.combat.current.round == 1) {
+ if (Misc.isFirstConnectedGM() && game.combat.current.round == 1) {
let initMissing = game.combat.combatants.find(it => !it.initiative);
if (!initMissing) { // Premier round !
for (let combatant of game.combat.combatants) {
@@ -454,10 +454,10 @@ export class RdDCombat {
/* -------------------------------------------- */
static combatNouveauTour(combat) {
- if (Misc.isUniqueConnectedGM()) {
+ if (Misc.isFirstConnectedGM()) {
let turn = combat.turns.find(t => t.token?.id == combat.current.tokenId);
if (turn?.actor) {
- RdDCombat.displayActorCombatStatus(combat, turn.actor, turn.token.id);
+ RdDCombat.displayActorCombatStatus(combat, turn.actor, turn.token);
// TODO Playaudio for player??
}
}
@@ -469,52 +469,51 @@ export class RdDCombat {
}
/* -------------------------------------------- */
- static rddCombatTarget(target, attacker) {
- const defender = target?.actor;
- const defenderTokenId = target?.id;
- return new RdDCombat(attacker, defender, defenderTokenId, target)
+ static rddCombatTarget(target, attacker, attackerToken) {
+ return new RdDCombat(attacker, attackerToken?.id, target?.actor, target?.id, target)
}
/* -------------------------------------------- */
- static rddCombatForAttackerAndDefender(attackerId, defenderTokenId) {
- const attacker = game.actors.get(attackerId);
- let defender = defenderTokenId ? canvas.tokens.get(defenderTokenId)?.actor : undefined;
+ static rddCombatForAttackerAndDefender(attackerId, attackerTokenId, defenderTokenId) {
+ const attacker = game.actors.get(attackerId)
+ const defenderToken = defenderTokenId ? canvas.tokens.get(defenderTokenId) : undefined
+ let defender = defenderToken?.actor;
let target = undefined
if (!defenderTokenId || !defender) {
console.warn(`RdDCombat.rddCombatForAttackerAndDefender: appel avec defenderTokenId ${defenderTokenId} incorrect, ou pas de defender correspondant`);
target = Targets.getTarget()
if (!target) {
- return;
+ return
}
defenderTokenId = target.id;
defender = target.actor;
if (!defenderTokenId || !defender) {
- return;
+ return
}
}
- return new RdDCombat(attacker, defender, defenderTokenId, target)
+ return new RdDCombat(attacker, attackerTokenId, defender, defenderTokenId, target)
}
/* -------------------------------------------- */
static onMsgEncaisser(msg) {
- let defender = canvas.tokens.get(msg.defenderTokenId).actor;
if (Misc.isOwnerPlayerOrUniqueConnectedGM()) {
let attackerRoll = msg.attackerRoll;
let attacker = msg.attackerId ? game.actors.get(msg.attackerId) : undefined;
+ let defender = canvas.tokens.get(msg.defenderToken.id).actor;
- defender.encaisserDommages(attackerRoll, attacker);
- const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.defenderTokenId);
+ defender.encaisserDommages(attackerRoll, attacker, msg.attackerToken);
+ const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.attackerToken.id, msg.defenderToken.id);
rddCombat?.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
}
}
/* -------------------------------------------- */
static onMsgDefense(msg) {
- let defenderToken = canvas.tokens.get(msg.defenderTokenId);
- if (defenderToken && Misc.isUniqueConnectedGM()) {
- const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.defenderTokenId);
- rddCombat?.removeChatMessageActionsPasseArme(msg.defenderRoll.passeArme);
- rddCombat?._chatMessageDefense(msg.paramChatDefense, msg.defenderRoll);
+ let defenderToken = canvas.tokens.get(msg.defenderToken.id)
+ if (defenderToken && Misc.isFirstConnectedGM()) {
+ const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.attackerToken.id, msg.defenderToken.id)
+ rddCombat?.removeChatMessageActionsPasseArme(msg.defenderRoll.passeArme)
+ rddCombat?._chatMessageDefense(msg.paramChatDefense, msg.defenderRoll)
}
}
@@ -545,6 +544,7 @@ export class RdDCombat {
html.on("click", button, event => {
const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(
event.currentTarget.attributes['data-attackerId']?.value,
+ event.currentTarget.attributes['data-attackerTokenId']?.value,
event.currentTarget.attributes['data-defenderTokenId']?.value);
if (rddCombat) {
rddCombat.onEvent(button, event);
@@ -560,22 +560,38 @@ export class RdDCombat {
}
/* -------------------------------------------- */
- constructor(attacker, defender, defenderTokenId, target) {
+ constructor(attacker, attackerTokenId, defender, defenderTokenId, target) {
this.attacker = attacker
this.defender = defender
this.target = target
this.attackerId = this.attacker.id
this.defenderId = this.defender.id
+ this.attackerTokenId = attackerTokenId
this.defenderTokenId = defenderTokenId
+ this.attackerToken = RdDCombat.$extractAttackerTokenData(attacker, attackerTokenId)
+ this.defenderToken = RdDCombat.$extractDefenderTokenData(defender, defenderTokenId, target)
}
+ static $extractAttackerTokenData(attacker, attackerTokenId) {
+ const token = canvas.tokens.get(attackerTokenId);
+ return token ? Targets.extractTokenData(token) : Targets.buildActorTokenData(attackerTokenId, attacker)
+ }
+
+ static $extractDefenderTokenData(defender, defenderTokenId, target) {
+ if (target) {
+ return Targets.extractTokenData(target)
+ }
+ const token = canvas.tokens.get(defenderTokenId);
+ return token ? Targets.extractTokenData(token) : Targets.buildActorTokenData(defenderTokenId, defender)
+ }
+
+
/* -------------------------------------------- */
async onEvent(button, event) {
const chatMessage = ChatUtility.getChatMessage(event);
const defenderRoll = ChatUtility.getMessageData(chatMessage, 'defender-roll');
const attackerRoll = defenderRoll?.attackerRoll ?? ChatUtility.getMessageData(chatMessage, 'attacker-roll');
console.log('RdDCombat', attackerRoll, defenderRoll);
- const defenderTokenId = event.currentTarget.attributes['data-defenderTokenId']?.value;
const armeParadeId = event.currentTarget.attributes['data-armeid']?.value;
const competence = event.currentTarget.attributes['data-competence']?.value;
@@ -585,7 +601,7 @@ export class RdDCombat {
case '#particuliere-attaque': return await this.choixParticuliere(attackerRoll, event.currentTarget.attributes['data-mode'].value);
case '#parer-button': return this.parade(attackerRoll, armeParadeId);
case '#esquiver-button': return this.esquive(attackerRoll, compId, competence);
- case '#encaisser-button': return this.encaisser(attackerRoll, defenderRoll, defenderTokenId);
+ case '#encaisser-button': return this.encaisser(attackerRoll, defenderRoll);
case '#echec-total-attaque': return this._onEchecTotal(attackerRoll);
case '#appel-chance-attaque': return this.attacker.rollAppelChance(
@@ -702,7 +718,7 @@ export class RdDCombat {
})
}
else {
- const defenderToken = canvas.tokens.get(this.defenderTokenId);
+ const defenderToken = canvas.tokens.get(this.defenderTokenId)
const dist = this.distance(_token, defenderToken)
const isVisible = this.isVisible(_token, defenderToken)
const portee = this._ajustementPortee(dist, rollData.arme)
@@ -769,7 +785,7 @@ export class RdDCombat {
}
RdDEmpoignade.checkEmpoignadeEnCours(this.attacker)
- let rollData = this._prepareAttaque(competence, arme);
+ let rollData = this._prepareAttaque(competence, arme)
console.log("RdDCombat.attaque >>>", rollData);
if (arme) {
this.attacker.verifierForceMin(arme);
@@ -795,18 +811,21 @@ export class RdDCombat {
dialog.render(true);
}
+
/* -------------------------------------------- */
_prepareAttaque(competence, arme) {
let rollData = {
+ alias: this.attackerToken.name,
passeArme: foundry.utils.randomID(16),
mortalite: arme?.system.mortalite,
competence: competence,
surprise: this.attacker.getSurprise(true),
surpriseDefenseur: this.defender.getSurprise(true),
- targetToken: Targets.extractTokenData(this.target),
+ sourceToken: this.attackerToken,
+ targetToken: this.defenderToken,
essais: {}
};
-
+
if (this.attacker.isCreatureEntite()) {
RdDItemCompetenceCreature.setRollDataCreature(rollData);
}
@@ -848,9 +867,10 @@ export class RdDCombat {
alias: this.attacker.name,
whisper: ChatUtility.getOwners(this.attacker),
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-particuliere.html', {
- alias: this.attacker.name,
+ alias: this.attackerToken.name,
attackerId: this.attackerId,
- defenderTokenId: this.defenderTokenId,
+ attackerToken: this.attackerToken,
+ defenderToken: this.defenderToken,
isForce: isForce,
isFinesse: isFinesse,
isRapide: isRapide,
@@ -867,7 +887,7 @@ export class RdDCombat {
attackerRoll.dmg = RdDBonus.dmg(attackerRoll, this.attacker, this.defender.isEntite());
let defenderRoll = { attackerRoll: attackerRoll, passeArme: attackerRoll.passeArme, show: {} }
attackerRoll.show = {
- cible: this.target ? this.defender.name : 'la cible',
+ cible: this.defenderToken?.name ?? 'la cible',
isRecul: (attackerRoll.particuliere == 'force' || attackerRoll.tactique == 'charge')
}
await RdDResolutionTable.displayRollData(attackerRoll, this.attacker, 'chat-resultat-attaque.html');
@@ -908,7 +928,8 @@ export class RdDCombat {
attacker: this.attacker,
attackerId: this.attackerId,
esquives: esquives,
- defenderTokenId: this.defenderTokenId,
+ attackerToken: this.attackerToken,
+ defenderToken: this.defenderToken,
mainsNues: attackerRoll.dmg.mortalite != 'mortel' && corpsACorps,
armes: this._filterArmesParade(this.defender, attackerRoll.competence, attackerRoll.arme),
diffLibre: attackerRoll.ajustements?.diffLibre?.value ?? 0,
@@ -919,7 +940,7 @@ export class RdDCombat {
dmg: attackerRoll.dmg,
};
- if (Misc.isUniqueConnectedGM()) {
+ if (Misc.isFirstConnectedGM()) {
await this._chatMessageDefense(paramChatDefense, defenderRoll);
}
else {
@@ -932,7 +953,7 @@ export class RdDCombat {
const choixDefense = await ChatMessage.create({
// message privé: du défenseur à lui même (et aux GMs)
speaker: ChatMessage.getSpeaker(this.defender, canvas.tokens.get(this.defenderTokenId)),
- alias: this.attacker.name,
+ alias: this.attackerToken.name,
whisper: ChatUtility.getOwners(this.defender),
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-defense.html', paramDemandeDefense),
});
@@ -946,8 +967,9 @@ export class RdDCombat {
game.socket.emit(SYSTEM_SOCKET_ID, {
msg: "msg_defense", data: {
attackerId: this.attacker?.id,
+ attackerToken: this.attackerToken,
defenderId: this.defender?.id,
- defenderTokenId: this.defenderTokenId,
+ defenderToken: this.defenderToken,
defenderRoll: defenderRoll,
paramChatDefense: paramChatDefense,
rollMode: true
@@ -980,7 +1002,8 @@ export class RdDCombat {
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-etotal.html', {
attackerId: this.attackerId,
attacker: this.attacker,
- defenderTokenId: this.defenderTokenId,
+ attackerToken: this.attackerToken,
+ defenderToken: this.defenderToken,
essais: attackerRoll.essais
})
});
@@ -1052,8 +1075,11 @@ export class RdDCombat {
/* -------------------------------------------- */
_prepareParade(attackerRoll, armeParade, competenceParade) {
let defenderRoll = {
+ alias: this.defenderToken?.name,
passeArme: attackerRoll.passeArme,
diffLibre: attackerRoll.diffLibre,
+ attackerToken: this.attackerToken,
+ defenderToken: this.defenderToken,
attackerRoll: attackerRoll,
competence: this.defender.getCompetence(competenceParade),
arme: armeParade,
@@ -1133,8 +1159,11 @@ export class RdDCombat {
/* -------------------------------------------- */
_prepareEsquive(attackerRoll, competence) {
let rollData = {
+ alias: this.defenderToken?.name,
passeArme: attackerRoll.passeArme,
diffLibre: attackerRoll.diffLibre,
+ attackerToken: this.attackerToken,
+ defenderToken: this.defenderToken,
attackerRoll: attackerRoll,
competence: competence,
surprise: this.defender.getSurprise(true),
@@ -1276,9 +1305,8 @@ export class RdDCombat {
}
/* -------------------------------------------- */
- async encaisser(attackerRoll, defenderRoll, defenderTokenId) {
- defenderTokenId = defenderTokenId || this.defenderTokenId;
- console.log("RdDCombat.encaisser >>>", attackerRoll, defenderTokenId);
+ async encaisser(attackerRoll, defenderRoll) {
+ console.log("RdDCombat.encaisser >>>", attackerRoll, defenderRoll);
if (defenderRoll?.rolled && RdDCombat.isEchecTotal(defenderRoll)) {
this._onEchecTotal(defenderRoll);
@@ -1286,18 +1314,19 @@ export class RdDCombat {
if (Misc.isOwnerPlayerOrUniqueConnectedGM(this.defender)) {
attackerRoll.attackerId = this.attackerId;
- attackerRoll.defenderTokenId = defenderTokenId;
+ attackerRoll.defenderTokenId = this.defenderToken.id;
await this.computeRecul(defenderRoll);
- await this.defender.encaisserDommages(attackerRoll, this.attacker, defenderRoll?.show);
+ await this.defender.encaisserDommages(attackerRoll, this.attacker, defenderRoll?.show, this.attackerToken, this.defenderToken);
}
else { // envoi à un GM: les joueurs n'ont pas le droit de modifier les personnages qu'ils ne possèdent pas
game.socket.emit(SYSTEM_SOCKET_ID, {
msg: "msg_encaisser",
data: {
attackerId: this.attackerId,
- defenderTokenId: defenderTokenId,
- attackerRoll: attackerRoll
+ attackerRoll: attackerRoll,
+ attackerToken: this.attackerToken,
+ defenderToken: this.defenderToken
}
});
}
@@ -1305,28 +1334,28 @@ export class RdDCombat {
}
/* -------------------------------------------- */
- static async displayActorCombatStatus(combat, actor, tokenId) {
+ static async displayActorCombatStatus(combat, actor, token) {
let formData = {
combatId: combat._id,
- alias: actor.name,
+ alias: token.name ?? actor.name,
etatGeneral: actor.getEtatGeneral(),
isSonne: actor.getSonne(),
blessuresStatus: actor.computeResumeBlessure(),
SConst: actor.getSConst(),
actorId: actor.id,
actor: actor,
- tokenId: tokenId,
+ tokenId: token.id,
isGrave: actor.countBlessures(it => it.isGrave()) > 0,
isCritique: actor.countBlessures(it => it.isCritique()) > 0
}
await ChatMessage.create({
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-actor-turn-acteur.hbs`, formData),
- alias: actor.name
+ alias: token.name ?? actor.name
})
await ChatMessage.create({
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-actor-turn-sante.hbs`, formData),
whisper: ChatUtility.getOwners(actor),
- alias: actor.name
+ alias: token.name ?? actor.name
});
}
}
\ No newline at end of file
diff --git a/module/rdd-main.js b/module/rdd-main.js
index 18778107..e4c58875 100644
--- a/module/rdd-main.js
+++ b/module/rdd-main.js
@@ -278,7 +278,7 @@ export class SystemReveDeDragon {
/* Foundry VTT Initialization */
/* -------------------------------------------- */
game.system.rdd.calendrier = new RdDCalendrier()
- if (Misc.isUniqueConnectedGM()) {
+ if (Misc.isFirstConnectedGM()) {
new Migrations().migrate()
this.messageDeBienvenue()
import("https://www.uberwald.me/fvtt_appcount/count-class-ready.js").then(moduleCounter => {
diff --git a/module/rdd-roll-encaisser.js b/module/rdd-roll-encaisser.js
index a9fc2d84..14748a6e 100644
--- a/module/rdd-roll-encaisser.js
+++ b/module/rdd-roll-encaisser.js
@@ -72,6 +72,6 @@ export class RdDEncaisser extends Dialog {
encaisserSpecial: this.encaisserSpecial,
mortalite: mortalite
}
- });
+ })
}
}
diff --git a/module/rdd-token-hud.js b/module/rdd-token-hud.js
index 0cdf7adf..a230f8ee 100644
--- a/module/rdd-token-hud.js
+++ b/module/rdd-token-hud.js
@@ -37,7 +37,7 @@ export class RdDTokenHud {
// initiative
await RdDTokenHud.addExtensionHudInit(html, combatant, actions);
// combat
- await RdDTokenHud.addExtensionHudCombat(html, combatant, actions);
+ await RdDTokenHud.addExtensionHudCombat(html, combatant, token, actions);
}
@@ -68,8 +68,8 @@ export class RdDTokenHud {
});
}
- static async addExtensionHudCombat(html, combatant, actions) {
- const hudData = { combatant, actions, commandes: [] };
+ static async addExtensionHudCombat(html, combatant, token, actions) {
+ const hudData = { combatant, token, actions, commandes: [] };
const controlIconTarget = html.find('.control-icon[data-action=target]');
await RdDTokenHud._configureSubMenu(controlIconTarget, 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-attaque.html', hudData,
(event) => {
@@ -80,7 +80,7 @@ export class RdDTokenHud {
combatant.actor.conjurerPossession(possession);
}
else {
- combatant.actor.rollArme(action);
+ combatant.actor.rollArme(action, 'competence', token)
}
});
}
diff --git a/module/rdd-utility.js b/module/rdd-utility.js
index 20b10526..70950c74 100644
--- a/module/rdd-utility.js
+++ b/module/rdd-utility.js
@@ -563,14 +563,14 @@ export class RdDUtility {
}
/* -------------------------------------------- */
- static async jetEncaissement(rollData, armure, options = { showDice: HIDE_DICE }) {
+ static async jetEncaissement(actor, rollData, armure, options = { showDice: HIDE_DICE }) {
const diff = Math.abs(rollData.diffLibre);
let formula = RdDUtility.formuleEncaissement(diff, options)
const roll = await RdDDice.roll(formula, options);
RdDUtility.remplaceDeMinParDifficulte(roll, diff, options);
- return await RdDUtility.prepareEncaissement(rollData, roll, armure);
+ return await RdDUtility.prepareEncaissement(actor, rollData, roll, armure);
}
static remplaceDeMinParDifficulte(roll, diff, options) {
@@ -602,15 +602,20 @@ export class RdDUtility {
}
/* -------------------------------------------- */
- static async prepareEncaissement(rollData, roll, armure) {
+ static async prepareEncaissement(actor, rollData, roll, armure) {
// La difficulté d'ataque s'ajoute aux dégâts
const bonusDegatsDiffLibre = ReglesOptionnelles.isUsing('degat-ajout-malus-libre') ? Math.abs(rollData.diffLibre ?? 0) : 0
const jetTotal = roll.total + rollData.dmg.total - armure + bonusDegatsDiffLibre
const encaissement = RdDUtility._selectEncaissement(jetTotal, rollData.dmg.mortalite);
const over20 = Math.max(jetTotal - 20, 0);
- encaissement.dmg = rollData.dmg;
- encaissement.dmg.loc = rollData.dmg.loc ?? await RdDUtility.getLocalisation(this.type);
- encaissement.dmg.loc.label = encaissement.dmg.loc.label ?? 'Corps;';
+ encaissement.dmg = rollData.dmg
+ if (ReglesOptionnelles.isUsing('localisation-aleatoire')){
+ encaissement.dmg.loc = rollData.dmg.loc ?? await RdDUtility.getLocalisation(actor.type)
+ encaissement.dmg.loc.label = encaissement.dmg.loc.label ?? 'Corps;'
+ }
+ else{
+ encaissement.dmg.loc = {label:''}
+ }
encaissement.dmg.bonusDegatsDiffLibre = bonusDegatsDiffLibre
encaissement.roll = roll;
encaissement.armure = armure;
@@ -741,6 +746,15 @@ export class RdDUtility {
return undefined;
}
+ static getSelectedToken(actor) {
+ if (canvas.tokens.controlled.length > 0) {
+ const tokens = canvas.tokens.controlled
+ .filter(it => it.actor.id == actor.id)
+ return tokens[0]
+ }
+ return undefined
+ }
+
static getSelectedActor(msgPlayer = undefined) {
if (canvas.tokens.controlled.length == 1) {
let token = canvas.tokens.controlled[0];
diff --git a/module/settings/regles-optionnelles.js b/module/settings/regles-optionnelles.js
index 3eac1e2d..02c2cd60 100644
--- a/module/settings/regles-optionnelles.js
+++ b/module/settings/regles-optionnelles.js
@@ -11,6 +11,7 @@ const listeReglesOptionnelles = [
{ group: 'Récupération', name: 'recuperation-moral', descr: "Le moral revient vers 0 durant Château Dormant"},
+ { group: 'Règles de combat', name: 'localisation-aleatoire', descr: "Proposer une localisation aléatoire des blessures" },
{ group: 'Règles de combat', name: 'recul', descr: "Appliquer le recul en cas de particulière en force ou de charge" },
{ group: 'Règles de combat', name: 'resistanceArmeParade', descr: "Faire le jet de résistance des armes lors de parades pouvant les endommager" },
{ group: 'Règles de combat', name: 'deteriorationArmure', descr: "Tenir compte de la détérioration des armures" },
diff --git a/module/sommeil/app-astrologie.js b/module/sommeil/app-astrologie.js
index 0e33a748..e8727294 100644
--- a/module/sommeil/app-astrologie.js
+++ b/module/sommeil/app-astrologie.js
@@ -186,7 +186,7 @@ export class AppAstrologie extends Application {
date: this.html.find('[name="joursAstrologie"]').val(),
userId: game.user.id
}
- if (Misc.isUniqueConnectedGM()) {
+ if (Misc.isFirstConnectedGM()) {
game.system.rdd.calendrier.requestNombreAstral(socketData);
} else {
game.socket.emit(SYSTEM_SOCKET_ID, {
diff --git a/module/targets.js b/module/targets.js
index 09d83e5d..98f76f2a 100644
--- a/module/targets.js
+++ b/module/targets.js
@@ -13,18 +13,21 @@ export class Targets {
static extractTokenData(target) {
return { id: target?.id, name: target?.document.name, img: target?.document.texture.src ?? target?.actor.img ?? 'icons/svg/mystery-man.svg' };
}
-
+ static buildActorTokenData(tokenId, actor) {
+ return { id: tokenId, name: actor.name, img: actor.img ?? 'icons/svg/mystery-man.svg' };
+ }
static isTargetEntite(target) {
return target?.actor.type == 'entite' && target?.actor.system.definition.typeentite == ENTITE_NONINCARNE;
}
- static async selectOneToken(onSelectTarget = target => { }) {
- const targets = Targets.listTargets();
+ static async selectOneTargetToken(onSelectTarget = target => { }) {
+ const targets = Targets.listTargets()
switch (targets.length) {
- case 0: return;
+ case 0:
+ return
case 1:
- onSelectTarget(targets[0]);
- return;
+ onSelectTarget(targets[0])
+ return
default:
{
const selectData = {
@@ -32,7 +35,7 @@ export class Targets {
label: "Choisir une seule des cibles",
list: targets.map(it => Targets.extractTokenData(it))
};
- DialogSelect.select(selectData, onSelectTarget);
+ DialogSelect.select(selectData, onSelectTarget)
}
}
}
diff --git a/module/time/rdd-calendrier.js b/module/time/rdd-calendrier.js
index b2a4129d..727599c2 100644
--- a/module/time/rdd-calendrier.js
+++ b/module/time/rdd-calendrier.js
@@ -48,7 +48,7 @@ export class RdDCalendrier extends Application {
constructor() {
super();
this.timestamp = RdDTimestamp.getWorldTime();
- if (Misc.isUniqueConnectedGM()) { // Uniquement si GM
+ if (Misc.isFirstConnectedGM()) { // Uniquement si GM
RdDTimestamp.setWorldTime(this.timestamp);
this.rebuildNombresAstraux(); // Ensure always up-to-date
}
@@ -258,7 +258,7 @@ export class RdDCalendrier extends Application {
/* -------------------------------------------- */
async rebuildNombresAstraux() {
- if (Misc.isUniqueConnectedGM()) {
+ if (Misc.isFirstConnectedGM()) {
const nombresAstraux = this.getNombresAstraux()
let newNombresAstraux = [];
for (let i = 0; i < MAX_NOMBRE_ASTRAL; i++) {
@@ -337,7 +337,7 @@ export class RdDCalendrier extends Application {
/* -------------------------------------------- */
async requestNombreAstral(request) {
const actor = game.actors.get(request.id);
- if (Misc.isUniqueConnectedGM()) { // Only once
+ if (Misc.isFirstConnectedGM()) { // Only once
console.log(request);
let jourDiff = this.getLectureAstrologieDifficulte(request.date);
let niveau = Number(request.astrologie.system.niveau) + Number(request.conditions) + Number(jourDiff) + Number(request.etat);
diff --git a/styles/simple.css b/styles/simple.css
index 491e0f7b..f9eb048f 100644
--- a/styles/simple.css
+++ b/styles/simple.css
@@ -1561,6 +1561,11 @@ div.control-icon.token-hud-icon {
height: 100%;
object-fit: contain;
}
+.chat-inline-icon {
+ border: 0;
+ padding: 1px;
+ vertical-align: text-top;
+}
#sidebar-tabs {
flex: 0 0 28px;
diff --git a/system.json b/system.json
index a92ba9db..c2c2c221 100644
--- a/system.json
+++ b/system.json
@@ -1,8 +1,8 @@
{
"id": "foundryvtt-reve-de-dragon",
"title": "Rêve de Dragon",
- "version": "12.0.15",
- "download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-12.0.15.zip",
+ "version": "12.0.17",
+ "download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-12.0.17.zip",
"manifest": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/v11/system.json",
"changelog": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/branch/v11/changelog.md",
"compatibility": {
diff --git a/templates/actor/export-scriptarium/actor-encart-sheet.hbs b/templates/actor/export-scriptarium/actor-encart-sheet.hbs
index 91d943e6..1368d560 100644
--- a/templates/actor/export-scriptarium/actor-encart-sheet.hbs
+++ b/templates/actor/export-scriptarium/actor-encart-sheet.hbs
@@ -1,11 +1,17 @@