diff --git a/changelog.md b/changelog.md
index ad50c309..b696159d 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,4 +1,25 @@
# 12.0
+## 12.0.18 - A la barbe d'Astrobazzarh
+- Améliorations sur la feuille de PNJ simplifiée
+ - Ajout du portrait
+ - Ajout du corps à corps
+ - Affichage du niveau d'esquive
+ - Un clic sur l'initiative permet de lancer l'initiative
+ - les boutons +/- pour la vie, l'endurance et la fatigue changent si on est à la valeur normale
+ - un clic sur l'endurance effectue un jet d'endurance
+- Fix
+ - les achats des commerces sont de nouveau possibles
+ - la commande /astro fonctionne de nouveau
+ - le nombre d'utilisations d'items est réinitialisé à chaque round et fin de combat
+ - la difficulté de parade pour les armes à distances n'est plus indiquée
+ - les propositions d'armes de parade sont corrigées
+- Ajout d'un indicateur pour les armes de parade nécessitant une significative
+
+## 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..1b2f7abf 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);
+ this.html.find('.roll-init-arme').click(async event => {
+ 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..75eec4e8 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)
@@ -2615,7 +2615,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async resetItemUse() {
- await this.setFlag(SYSTEM_RDD, 'itemUse', {});
+ await this.unsetFlag(SYSTEM_RDD, 'itemUse');
}
/* -------------------------------------------- */
@@ -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..53b5604b 100644
--- a/module/actor/base-actor-reve.js
+++ b/module/actor/base-actor-reve.js
@@ -78,8 +78,10 @@ export class RdDBaseActorReve extends RdDBaseActor {
}
async jetEndurance(resteEndurance = undefined) { return { jetEndurance: 0, sonne: false } }
isDead() { return false }
+ isSonne() { return false }
blessuresASoigner() { return [] }
getEtatGeneral(options = { ethylisme: false }) { return 0 }
+ isActorCombat() { return true }
async computeArmure(attackerRoll) { return this.getProtectionNaturelle() }
async remiseANeuf() { }
@@ -327,14 +329,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 +367,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 +389,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 +399,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);
})
}
@@ -403,58 +407,52 @@ export class RdDBaseActorReve extends RdDBaseActor {
return RdDItemArme.getCompetenceArme(arme, competenceName)
}
- verifierForceMin(item) {
- }
- /* -------------------------------------------- */
- async resetItemUse() { }
- async incDecItemUse(itemId, inc = 1) { }
- getItemUse(itemId) { return 0; }
+ verifierForceMin(item) { }
/* -------------------------------------------- */
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..26a58350 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;
}
@@ -276,11 +276,11 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
ui.notifications.info(`${this.name} est hors combat, il ne reste donc pas sonné`);
return;
}
- await this.setEffect(STATUSES.StatusStunned, sonne);
+ await this.setEffect(STATUSES.StatusStunned, sonne)
}
- getSonne() {
- return this.getEffect(STATUSES.StatusStunned);
+ isSonne() {
+ return this.getEffect(STATUSES.StatusStunned)
}
isEffectAllowed(effectId) { return true }
diff --git a/module/actor/base-actor.js b/module/actor/base-actor.js
index 57fbcb07..7d8b64ab 100644
--- a/module/actor/base-actor.js
+++ b/module/actor/base-actor.js
@@ -205,11 +205,8 @@ export class RdDBaseActor extends Actor {
/* -------------------------------------------- */
async onPreUpdateItem(item, change, options, id) { }
-
async onCreateItem(item, options, id) { }
-
async onDeleteItem(item, options, id) { }
-
async onUpdateActor(update, options, actorId) { }
async onTimeChanging(oldTimestamp, newTimestamp) {
@@ -218,7 +215,7 @@ export class RdDBaseActor extends Actor {
}
async creerObjetParMJ(object) {
- if (!Misc.isUniqueConnectedGM()) {
+ if (!Misc.isFirstConnectedGM()) {
RdDBaseActor.remoteActorCall({
tokenId: this.token?.id,
actorId: this.id,
@@ -317,7 +314,7 @@ export class RdDBaseActor extends Actor {
RdDAudio.PlayContextAudio("argent"); // Petit son
ChatMessage.create({
- whisper: ChatUtility.getOwners(this.name),
+ whisper: ChatUtility.getOwners(this),
content: `Vous avez reçu ${sols} Sols ${fromActor ? " de " + fromActor.name : ''}, qui ont été ajoutés à votre argent.`
});
}
@@ -335,7 +332,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',
@@ -708,5 +705,9 @@ export class RdDBaseActor extends Actor {
}
return undefined
}
-
+ async resetItemUse() { }
+ async incDecItemUse(itemId, inc = 1) { }
+ getItemUse(itemId) { return 0; }
+ async finDeRound(options = { terminer: false }) { }
+ isActorCombat() { return false }
}
\ No newline at end of file
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..8a4cd515 100644
--- a/module/actor/export-scriptarium/mapping.js
+++ b/module/actor/export-scriptarium/mapping.js
@@ -84,7 +84,7 @@ const MAPPING_BASE = [
{ column: "malus_armure", getter: (actor, context) => Mapping.getMalusArmure(actor, context) },
{ column: "reve_actuel", rollClass: 'roll-reve-actuel', colName: 'Rêve actuel', getter: (actor, context) => actor.system.reve.reve.value },
{ column: "vie_actuel", rollClass: 'jet-vie', getter: (actor, context) => actor.system.sante.vie.value },
- { column: "endurance_actuel", rollClass: 'jet-vie', getter: (actor, context) => actor.system.sante.endurance.value },
+ { column: "endurance_actuel", rollClass: 'jet-endurance', getter: (actor, context) => actor.system.sante.endurance.value },
{ column: "esquive", getter: (actor, context) => Mapping.getEsquive(context) },
{ column: "esquive_armure", getter: (actor, context) => Mapping.getEsquiveArmure(context) },
{ column: "competences", getter: (actor, context) => Mapping.getCompetences(actor, CATEGORIES_COMPETENCES) },
@@ -140,16 +140,15 @@ export class Mapping {
static prepareArmes(actor) {
const armes = actor.items.filter(it => it.type == ITEM_TYPES.arme)
- return armes.map(arme =>
- [
- arme.system.unemain ? Mapping.prepareArme(actor, arme, 'unemain') : undefined,
- arme.system.deuxmains ? Mapping.prepareArme(actor, arme, 'deuxmains') : undefined,
- !(arme.system.unemain || arme.system.deuxmains) ? Mapping.prepareArme(actor, arme, 'competence') : undefined,
- arme.system.lancer != "" ? Mapping.prepareArme(actor, arme, 'lancer') : undefined,
- arme.system.tir != "" ? Mapping.prepareArme(actor, arme, 'tir') : undefined
- ]
- .filter(it => it != undefined)
- ).reduce((a, b) => a.concat(b), [])
+ RdDItemArme.ajoutCorpsACorps(armes, actor)
+ return armes.map(arme => [
+ arme.system.unemain ? Mapping.prepareArme(actor, arme, 'unemain') : undefined,
+ arme.system.deuxmains ? Mapping.prepareArme(actor, arme, 'deuxmains') : undefined,
+ !(arme.system.unemain || arme.system.deuxmains) ? Mapping.prepareArme(actor, arme, 'competence') : undefined,
+ arme.system.lancer != "" ? Mapping.prepareArme(actor, arme, 'lancer') : undefined,
+ arme.system.tir != "" ? Mapping.prepareArme(actor, arme, 'tir') : undefined]
+ .filter(it => it != undefined))
+ .reduce((a, b) => a.concat(b), [])
}
static prepareArme(actor, arme, maniement) {
@@ -158,27 +157,35 @@ export class Mapping {
if (RdDItemCompetence.isNiveauBase(competence)) {
return undefined
}
- const dmgArme = RdDItemArme.dommagesReels(arme, maniement)
- const dommages = dmgArme + RdDBonus.bonusDmg(actor, maniement, dmgArme)
const categorie = Mapping.complementCategorie(arme, maniement)
+ const dommages = Mapping.dommagesArme(actor, arme, maniement)
return {
name: arme.name + categorie,
niveau: Misc.toSignedString(competence.system.niveau),
init: Mapping.calculBaseInit(actor, competence.system.categorie) + competence.system.niveau,
- dommages: Misc.toSignedString(dommages),
+ dommages: dommages,
competence: competence,
arme: arme
}
}
+ static dommagesArme(actor, arme, maniement){
+ const dmgArme = RdDItemArme.dommagesReels(arme, maniement)
+ const dommages = Misc.toSignedString(dmgArme + RdDBonus.bonusDmg(actor, maniement, dmgArme))
+ switch(arme.system.mortalite) {
+ case 'non-mortel': return `(${dommages})`
+ case 'empoignade': return '-'
+ }
+ return dommages
+ }
static complementCategorie(arme, maniement) {
switch (maniement) {
- case 'unemain': return (arme.system.deuxmains) ? ' 1 main' : (arme.system.lancer||arme.system.tir) ? ' mêlée': ''
- case 'deuxmains': return (arme.system.unemain) ? ' 2 mains' : (arme.system.lancer||arme.system.tir) ? ' mêlée': ''
+ case 'unemain': return (arme.system.deuxmains) ? ' 1 main' : (arme.system.lancer || arme.system.tir) ? ' mêlée' : ''
+ case 'deuxmains': return (arme.system.unemain) ? ' 2 mains' : (arme.system.lancer || arme.system.tir) ? ' mêlée' : ''
case 'lancer': return (arme.system.unemain || arme.system.deuxmains || arme.system.tir) ? ' jet' : ''
case 'tir': return (arme.system.unemain || arme.system.deuxmains || arme.system.lancer) ? ' tir' : ''
}
- return ''
+ return ''
}
static calculBaseInit(actor, categorie) {
@@ -327,7 +334,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-arme.js b/module/item-arme.js
index 25cb4dd4..86255aa6 100644
--- a/module/item-arme.js
+++ b/module/item-arme.js
@@ -81,37 +81,59 @@ export class RdDItemArme extends Item {
/* -------------------------------------------- */
static getCategorieParade(armeData) {
if (armeData.system.categorie_parade) {
- return armeData.system.categorie_parade;
+ return armeData.system.categorie_parade
}
// pour compatibilité avec des personnages existants
if (armeData.type == ITEM_TYPES.competencecreature || armeData.system.categorie == 'creature') {
- return armeData.system.categorie_parade || (armeData.system.isparade ? 'armes-naturelles' : '');
+ return armeData.system.categorie_parade || (armeData.system.isparade ? 'armes-naturelles' : '')
}
if (!armeData.type.match(/arme|competencecreature/)) {
- return '';
+ return ''
}
if (armeData.system.competence == undefined) {
return ITEM_TYPES.competencecreature;
}
let compname = armeData.system.competence.toLowerCase();
- if (compname.match(/^(dague de jet|javelot|fouet|arc|arbalête|fronde|hache de jet|fléau)$/)) return '';
+ if (compname.match(/^(dague de jet|javelot|fouet|arc|arbalête|fronde|hache de jet|fléau)$/)) {
+ return ''
+ }
- if (compname.match('hache')) return 'haches';
- if (compname.match('hast')) return 'hast';
- if (compname.match('lance')) return 'lances';
- if (compname.match('bouclier')) return 'boucliers';
- if (compname.match('masse')) return 'masses';
+ if (compname.match('hache')) return 'haches'
+ if (compname.match('hast')) return 'hast'
+ if (compname.match('lance')) return 'lances'
+ if (compname.match('bouclier')) return 'boucliers'
+ if (compname.match('masse')) return 'masses'
if (compname.match('epée') || compname.match('épée')) {
if (armeData.name.toLowerCase().match(/(gnome)/))
- return 'epees-courtes';
+ return 'epees-courtes'
if (armeData.name.toLowerCase().match(/((e|é)pée dragone|esparlongue|demi-dragonne)/))
- return 'epees-longues';
- return 'epees-lourdes';
+ return 'epees-longues'
+ return 'epees-lourdes'
}
if (compname.match('dague')) {
- return 'dagues';
+ return 'dagues'
+ }
+ return 'sans-armes'
+ }
+
+ static defenseArmeParade(armeAttaque, armeParade) {
+ const defCategory = RdDItemArme.getCategorieParade(armeParade)
+ if (defCategory == 'bouclier') {
+ return 'norm'
+ }
+ if (armeAttaque.system.competence.toLowerCase().match(/(fléau)/)) {
+ return ''
+ }
+ if (armeParade.system.tir) {
+ return ''
+ }
+ const attCategory = RdDItemArme.getCategorieParade(armeAttaque)
+ switch (attCategory) {
+ case 'armes-naturelles': case 'sans-armes':
+ return defCategory == 'sans-armes' ? 'norm' : ''
+ default:
+ return RdDItemArme.needParadeSignificative(armeAttaque, armeParade) ? 'sign' : 'norm'
}
- return 'sans-armes';
}
/* -------------------------------------------- */
@@ -120,8 +142,8 @@ export class RdDItemArme extends Item {
return false;
}
// categories d'armes à la parade (cf. page 115 )
- let attCategory = RdDItemArme.getCategorieParade(armeAttaque);
- let defCategory = RdDItemArme.getCategorieParade(armeParade);
+ const attCategory = RdDItemArme.getCategorieParade(armeAttaque)
+ const defCategory = RdDItemArme.getCategorieParade(armeParade)
// bouclier et mêmes catégorie: peuvent se parer sans difficulté
if (defCategory == 'boucliers') {
return false;
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/item/blessure.js b/module/item/blessure.js
index 14c63724..b527249b 100644
--- a/module/item/blessure.js
+++ b/module/item/blessure.js
@@ -67,7 +67,7 @@ export class RdDItemBlessure extends RdDItem {
}
- static async createBlessure(actor, gravite, localisation = '', attacker) {
+ static async createBlessure(actor, gravite, localisation = '', attackerToken) {
const definition = RdDItemBlessure.getDefinition(gravite)
const blessure = {
name: definition.label,
@@ -77,7 +77,7 @@ export class RdDItemBlessure extends RdDItem {
gravite: gravite,
difficulte: - gravite,
localisation: localisation,
- origine: attacker?.name ?? ""
+ origine: attackerToken?.name ?? ""
}
}
const blessures = await actor.createEmbeddedDocuments('Item', [blessure])
diff --git a/module/misc.js b/module/misc.js
index c22fe21e..76a93ff3 100644
--- a/module/misc.js
+++ b/module/misc.js
@@ -139,7 +139,7 @@ export class Misc {
}
static join(params, separator = '') {
- return params?.reduce(Misc.joining(separator)) ?? '';
+ return (!params || params.length == 0) ? '' : params.reduce(Misc.joining(separator))
}
static joining(separator = '') {
@@ -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..35b6bf9f 100644
--- a/module/rdd-combat.js
+++ b/module/rdd-combat.js
@@ -42,7 +42,8 @@ export class RdDCombatManager extends Combat {
/* -------------------------------------------- */
Hooks.on("getCombatTrackerEntryContext", (html, options) => { RdDCombatManager.pushInitiativeOptions(html, options); });
Hooks.on("updateCombat", (combat, change, options, userId) => { RdDCombat.onUpdateCombat(combat, change, options, userId) });
- Hooks.on("preDeleteCombat", (combat, html, id) => { combat.onPreDeleteCombat() });
+ Hooks.on("preDeleteCombat", (combat, html, id) => { combat.onPreDeleteCombat() })
+ Hooks.on("deleteCombat", (combat, html, id) => { combat.onDeleteCombat() })
}
/* -------------------------------------------- */
@@ -53,7 +54,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)
@@ -61,20 +62,31 @@ export class RdDCombatManager extends Combat {
RdDEmpoignade.deleteAllEmpoignades()
}
}
-
- /* -------------------------------------------- */
- async finDeRound(options = { terminer: false }) {
- this.turns.forEach(turn => turn.actor.resetItemUse());
-
- for (let combatant of this.combatants) {
- if (combatant.actor) {
- await combatant.actor.finDeRound(options);
- }
- else {
- ui.notifications.warn(`Le combatant ${combatant.name} n'est pas associé à un acteur!`)
+ async onDeleteCombat() {
+ if (Misc.isFirstConnectedGM()) {
+ if (game.combats.size <= 1) {
+ game.actors.forEach(actor => actor.resetItemUse())
}
}
}
+
+ /* -------------------------------------------- */
+ async finDeRound(options = { terminer: false }) {
+
+ for (let combatant of this.combatants) {
+ if (!combatant.actor) {
+ ui.notifications.warn(`Le combatant ${combatant.name} n'est pas associé à un acteur!`)
+ }
+ else if (!combatant.actor.isActorCombat()) {
+ ui.notifications.warn(`Le combatant ${combatant.name} ne peut pas combattre!`)
+ }
+ else {
+ await combatant.actor.finDeRound(options)
+ await combatant.actor.resetItemUse()
+ }
+ }
+ }
+
static calculAjustementInit(actor, arme) {
const efficacite = (arme?.system.magique) ? arme.system.ecaille_efficacite : 0
const etatGeneral = actor.getEtatGeneral() ?? 0
@@ -125,7 +137,6 @@ export class RdDCombatManager extends Combat {
}
}
}
- //console.log("Combatat", c);
const roll = combatant.getInitiativeRoll(rollFormula);
if (!roll.total) {
await roll.evaluate();
@@ -236,29 +247,12 @@ export class RdDCombatManager extends Combat {
return attaque;
}
- static listActionsCreature(competences) {
- return competences
- .filter(it => RdDItemCompetenceCreature.isCompetenceAttaque(it))
- .map(it => RdDItemCompetenceCreature.armeCreature(it))
- .filter(it => it != undefined);
- }
-
- static listActionsPossessions(actor) {
- return RdDCombatManager._indexActions(actor.getPossessions().map(p => {
- return {
- name: p.name,
- action: 'possession',
- system: {
- competence: p.name,
- possessionid: p.system.possessionid,
- }
- }
- }));
- }
-
/* -------------------------------------------- */
static listActionsCombat(combatant) {
const actor = combatant.actor;
+ if (!actor.isActorCombat()) {
+ return
+ }
let actions = RdDCombatManager.listActionsPossessions(actor);
if (actions.length > 0) {
return actions;
@@ -281,6 +275,26 @@ export class RdDCombatManager extends Combat {
return RdDCombatManager._indexActions(actions);
}
+ static listActionsCreature(competences) {
+ return competences
+ .filter(it => RdDItemCompetenceCreature.isCompetenceAttaque(it))
+ .map(it => RdDItemCompetenceCreature.armeCreature(it))
+ .filter(it => it != undefined);
+ }
+
+ static listActionsPossessions(actor) {
+ return RdDCombatManager._indexActions(actor.getPossessions().map(p => {
+ return {
+ name: p.name,
+ action: 'possession',
+ system: {
+ competence: p.name,
+ possessionid: p.system.possessionid,
+ }
+ }
+ }));
+ }
+
static _indexActions(actions) {
for (let index = 0; index < actions.length; index++) {
actions[index].index = index;
@@ -291,7 +305,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,11 +468,11 @@ 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);
// TODO Playaudio for player??
+ RdDCombat.displayActorCombatStatus(combat, turn.actor, turn.token);
}
}
}
@@ -469,52 +483,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 +558,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 +574,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 +615,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 +732,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 +799,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,15 +825,18 @@ 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: {}
};
@@ -848,9 +881,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 +901,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');
@@ -898,7 +932,7 @@ export class RdDCombat {
// # utilisation esquive
const corpsACorps = this.defender.getCompetenceCorpsACorps({ onMessage: it => console.info(it, this.defender) });
const esquives = foundry.utils.duplicate(this.defender.getCompetencesEsquive())
- esquives.forEach(e => e.system.nbUsage = e?._id ? this.defender.getItemUse(e._id) : 0);
+ esquives.forEach(e => e.nbUsage = e?._id ? this.defender.getItemUse(e._id) : 0);
const paramChatDefense = {
passeArme: attackerRoll.passeArme,
@@ -908,7 +942,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 +954,7 @@ export class RdDCombat {
dmg: attackerRoll.dmg,
};
- if (Misc.isUniqueConnectedGM()) {
+ if (Misc.isFirstConnectedGM()) {
await this._chatMessageDefense(paramChatDefense, defenderRoll);
}
else {
@@ -932,7 +967,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 +981,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
@@ -956,20 +992,21 @@ export class RdDCombat {
}
/* -------------------------------------------- */
- _filterArmesParade(defender, competence) {
- let items = defender.items.filter(it => RdDItemArme.isArmeUtilisable(it) || RdDItemCompetenceCreature.isCompetenceParade(it))
- items.forEach(item => item.system.nbUsage = defender.getItemUse(item.id)); // Ajout du # d'utilisation ce round
+ _filterArmesParade(defender, competence, arme) {
+ let defenses = defender.items.filter(it => RdDItemArme.isArmeUtilisable(it) || RdDItemCompetenceCreature.isCompetenceParade(it))
+ defenses = foundry.utils.duplicate(defenses)
+ defenses.forEach(armeDefense => {
+ // Ajout du # d'utilisation ce round
+ armeDefense.nbUsage = defender.getItemUse(armeDefense.id)
+ armeDefense.typeParade = RdDItemArme.defenseArmeParade(arme, armeDefense)
+ })
switch (competence.system.categorie) {
case 'tir':
case 'lancer':
- return items.filter(item => RdDItemArme.getCategorieParade(item) == 'boucliers')
+ return defenses.filter(armeDefense => RdDItemArme.getCategorieParade(armeDefense) == 'boucliers')
default:
- // Le fléau ne peut être paré qu’au bouclier p115
- if (competence.name == "Fléau") {
- return items.filter(item => RdDItemArme.getCategorieParade(item) == 'boucliers')
- }
- return items.filter(item => RdDItemArme.getCategorieParade(item));
+ return defenses.filter(armeDefense => armeDefense.typeParade != '')
}
}
@@ -980,7 +1017,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 +1090,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 +1174,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 +1320,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 +1329,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 +1349,31 @@ export class RdDCombat {
}
/* -------------------------------------------- */
- static async displayActorCombatStatus(combat, actor, tokenId) {
+ static async displayActorCombatStatus(combat, actor, token) {
+ if (!actor?.isActorCombat()) {
+ return
+ }
let formData = {
combatId: combat._id,
- alias: actor.name,
+ alias: token.name ?? actor.name,
etatGeneral: actor.getEtatGeneral(),
- isSonne: actor.getSonne(),
+ isSonne: actor.isSonne(),
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 85331625..497fd5f3 100644
--- a/module/rdd-main.js
+++ b/module/rdd-main.js
@@ -280,7 +280,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..59bc9809 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];
@@ -867,10 +881,10 @@ export class RdDUtility {
/* -------------------------------------------- */
static afficherHeuresChanceMalchance(heureNaissance) {
if (game.user.isGM) {
- const heure = RdDTimestamp.findHeure(heureNaissance - 1);
+ const heure = RdDTimestamp.findHeure(heureNaissance)
if (heureNaissance && heure) {
- let ajustement = game.system.rdd.calendrier.getAjustementAstrologique(heureNaissance);
- const current = game.system.rdd.calendrier.heureCourante();
+ const ajustement = game.system.rdd.calendrier.getAjustementAstrologique(heureNaissance)
+ const current = game.system.rdd.calendrier.heureCourante()
ChatMessage.create({
content: `A l'heure de
${current.label}, le modificateur de Chance/Malchance est de
${Misc.toSignedString(ajustement)} pour l'heure de naissance
${heure.label}.`,
whisper: ChatUtility.getGMs()
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/module/time/rdd-timestamp.js b/module/time/rdd-timestamp.js
index 27a5a80f..b1cb827b 100644
--- a/module/time/rdd-timestamp.js
+++ b/module/time/rdd-timestamp.js
@@ -160,15 +160,21 @@ export class RdDTimestamp {
}
static findHeure(heure) {
- heure = Grammar.toLowerCaseNoAccentNoSpace(heure);
- let parHeureOuLabel = DEFINITION_HEURES.filter(it => Grammar.toLowerCaseNoAccentNoSpace(it.label) == heure || it.heure == Misc.modulo(parseInt(heure), RDD_HEURES_PAR_JOUR));
- if (parHeureOuLabel.length == 1) {
- return parHeureOuLabel[0];
+ let filtered
+ if (Number.isInteger(Number(heure))) {
+ filtered = DEFINITION_HEURES.filter(it => it.heure == Misc.modulo(Number(heure) - 1, RDD_HEURES_PAR_JOUR))
}
- let parLabelPartiel = DEFINITION_HEURES.filter(it => Grammar.toLowerCaseNoAccentNoSpace(it.label).includes(heure));
- if (parLabelPartiel.length > 0) {
- parLabelPartiel.sort(Misc.ascending(h => h.label.length));
- return parLabelPartiel[0];
+ else {
+ heure = Grammar.toLowerCaseNoAccentNoSpace(heure);
+ filtered = DEFINITION_HEURES.filter(it => Grammar.toLowerCaseNoAccentNoSpace(it.label) == heure || it.heure == Misc.modulo(parseInt(heure), RDD_HEURES_PAR_JOUR));
+ }
+ if (filtered.length == 1) {
+ return filtered[0]
+ }
+ filtered = DEFINITION_HEURES.filter(it => Grammar.toLowerCaseNoAccentNoSpace(it.label).includes(heure));
+ if (filtered.length > 0) {
+ filtered.sort(Misc.ascending(h => h.label.length));
+ return filtered[0]
}
return undefined;
}
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 c2c2c221..25c0e64d 100644
--- a/system.json
+++ b/system.json
@@ -1,8 +1,8 @@
{
"id": "foundryvtt-reve-de-dragon",
"title": "Rêve de Dragon",
- "version": "12.0.17",
- "download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-12.0.17.zip",
+ "version": "12.0.18",
+ "download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-12.0.18.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/combat.html b/templates/actor/combat.html
index 776f2b34..8179a27b 100644
--- a/templates/actor/combat.html
+++ b/templates/actor/combat.html
@@ -25,7 +25,7 @@
{{plusMoins arme.system.niveau}}
{{plusMoins arme.system.dommagesReels}}
-
{{arme.system.initiative}}
+
{{arme.system.initiative}}
{{/each}}
{{#each esquives as |esq key|}}
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 @@