diff --git a/module/actor.js b/module/actor.js
index 5e91f3c7..8b95cfe0 100644
--- a/module/actor.js
+++ b/module/actor.js
@@ -223,8 +223,18 @@ export class RdDActor extends Actor {
}
/* -------------------------------------------- */
getReveActuel() {
- return Misc.toInt(this.system.reve?.reve?.value ?? this.carac.reve.value);
+ switch(this.type) {
+ case 'personnage':
+ return Misc.toInt(this.system.reve?.reve?.value ?? this.carac.reve.value);
+ case 'creature':
+ case 'entite':
+ return Misc.toInt(this.system.carac.reve?.value)
+ case 'vehicule':
+ default:
+ return 0;
+ }
}
+
/* -------------------------------------------- */
getChanceActuel() {
return Misc.toInt(this.system.compteurs.chance?.value ?? 10);
@@ -2535,48 +2545,43 @@ export class RdDActor extends Actor {
}
/* -------------------------------------------- */
- async rollCompetence(idOrName) {
- let rollData = { competence: this.getCompetence(idOrName) }
-
+ async rollCompetence(idOrName, options = {tryTarget: true}) {
+ let rollData = {
+ carac: this.system.carac,
+ competence: this.getCompetence(idOrName)
+ }
if (rollData.competence.type == 'competencecreature') {
- if (rollData.competence.system.iscombat) {
- if (rollData.competence.system.ispossession) {
- RdDPossession.onAttaquePossession(this, rollData.competence)
- return
- }
- else if (RdDCombat.getTarget()) {
- const arme = RdDItemCompetenceCreature.toActionArme(rollData.competence)
- RdDCombat.createUsingTarget(this)?.attaque(competence, arme)
- return
+ if (rollData.competence.system.iscombat && options.tryTarget) {
+ const target = RdDCombat.getTarget();
+ if (target) {
+ if (rollData.competence.system.ispossession) {
+ RdDPossession.onAttaquePossession(target, this, rollData.competence)
+ }
+ else {
+ const arme = RdDItemCompetenceCreature.armeNaturelle(rollData.competence)
+ RdDCombat.rddCombatTarget(this, target).attaque(competence, arme)
+ }
+ return;
}
}
- // Fake competence pour créature
+ // Transformer la competence de créature
RdDItemCompetenceCreature.setRollDataCreature(rollData)
- } else {
- rollData.carac = this.system.carac
}
console.log("rollCompetence !!!", rollData);
-
const dialog = await RdDRoll.create(this, rollData, { html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html' }, {
name: 'jet-competence',
label: 'Jet ' + Grammar.apostrophe('de', rollData.competence.name),
callbacks: [
this.createCallbackExperience(),
this.createCallbackAppelAuMoral(),
- { action: r => this._competenceResult(r) }
+ { action: r => this.$onRollCompetence(r) }
]
});
dialog.render(true);
}
/* -------------------------------------------- */
- conjurerPossession(possession) {
- let draconic = this.getDraconicOuPossession();
- RdDPossession.onAttaquePossession(this, draconic, possession)
- }
-
- /* -------------------------------------------- */
- async _competenceResult(rollData) {
+ async $onRollCompetence(rollData) {
await RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-competence.html')
}
@@ -3217,26 +3222,42 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
rollArme(arme) {
- let competence = this.getCompetence(arme.system.competence)
- if (arme || (competence.type == 'competencecreature' && competence.system.iscombat)) {
- if (competence.system.ispossession) {
- RdDPossession.onAttaquePossession(this, competence);
- } else {
- RdDCombat.createUsingTarget(this)?.attaque(competence, arme);
- }
- } else {
- this.rollCompetence(competence.name);
+ const target = RdDCombat.getTarget();
+ if (!target) {
+ RdDConfirm.confirmer({
+ settingConfirmer: "confirmer-combat-sans-cible",
+ content: `
Voulez vous faire un jet de compétence ${arme.system.competence} sans choisir de cible valide?
+
Tous les jets de combats devront être gérés à la main
+
`,
+ title: 'Ne pas utiliser les automatisation de combat',
+ buttonLabel: "Pas d'automatisation",
+ onAction: async () => {
+ this.rollCompetence(arme.system.competence, {tryTarget: false})
+ }
+ });
+ return;
}
+ if (RdDCombat.isTargetEntite(target)){
+ ui.notifications.warn(`Vous ne pouvez pas attaquer une entité non incarnée avec votre ${arme.name}!!!!`);
+ return;
+ }
+ // if (RdDCombat.isTargetEntite(targets[0])) {
+ // ui.notifications.warn("Vous ne pouvez pas cibler une entité non incarnée!");
+ // return;
+ // }
+
+ const competence = this.getCompetence(arme.system.competence)
+ if (competence.system.ispossession) {
+ return RdDPossession.onAttaquePossession(target, this, competence);
+ }
+ RdDCombat.rddCombatTarget(this, target).attaque(competence, arme);
}
/* -------------------------------------------- */
- _getTarget() {
- if (game.user.targets && game.user.targets.size == 1) {
- for (let target of game.user.targets) {
- return target;
- }
- }
- return undefined;
+ conjurerPossession(possession) {
+ // TODO: choix de la compétence de draconic ou de possession
+ let draconic = this.getDraconicOuPossession();
+ RdDPossession.onConjurerPossession(this, draconic, possession)
}
/* -------------------------------------------- */
diff --git a/module/item-arme.js b/module/item-arme.js
index fdd86ac2..22118f78 100644
--- a/module/item-arme.js
+++ b/module/item-arme.js
@@ -28,7 +28,7 @@ export class RdDItemArme extends Item {
switch (arme ? arme.type : '') {
case 'arme': return arme;
case 'competencecreature':
- return RdDItemCompetenceCreature.toActionArme(arme);
+ return RdDItemCompetenceCreature.armeNaturelle(arme);
}
return RdDItemArme.mainsNues();
}
diff --git a/module/item-competencecreature.js b/module/item-competencecreature.js
index 1c59a285..e4311271 100644
--- a/module/item-competencecreature.js
+++ b/module/item-competencecreature.js
@@ -1,4 +1,4 @@
-import { Misc } from "./misc.js";
+
import { RdDCombatManager } from "./rdd-combat.js";
/* -------------------------------------------- */
@@ -12,12 +12,12 @@ export class RdDItemCompetenceCreature extends Item {
rollData.competence.system.categorie = "creature"
rollData.selectedCarac = rollData.carac.carac_creature
if (rollData.competence.system.iscombat) {
- rollData.arme = RdDItemCompetenceCreature.toActionArme(rollData.competence);
+ rollData.arme = RdDItemCompetenceCreature.armeNaturelle(rollData.competence);
}
}
/* -------------------------------------------- */
- static toActionArme(competencecreature) {
+ static armeNaturelle(competencecreature) {
if (RdDItemCompetenceCreature.isCompetenceAttaque(competencecreature)) {
// si c'est un Item compétence: cloner pour ne pas modifier lma compétence
let arme = (competencecreature instanceof Item) ? competencecreature.clone(): competencecreature;
diff --git a/module/rdd-combat.js b/module/rdd-combat.js
index 08c56b6a..ffdec171 100644
--- a/module/rdd-combat.js
+++ b/module/rdd-combat.js
@@ -222,7 +222,7 @@ export class RdDCombatManager extends Combat {
static listActionsCreature(competences) {
return competences.filter(it => RdDItemCompetenceCreature.isCompetenceAttaque(it))
- .map(it => RdDItemCompetenceCreature.toActionArme(it));
+ .map(it => RdDItemCompetenceCreature.armeNaturelle(it));
}
static listActionsPossessions(actor) {
@@ -470,51 +470,49 @@ export class RdDCombat {
}
/* -------------------------------------------- */
- static createUsingTarget(attacker) {
- const target = RdDCombat.getTarget()
- if (target == undefined) {
- ui.notifications.warn((game.user.targets?.size ?? 0) > 1
- ? "Vous devez choisir une seule cible à attaquer!"
- : "Vous devez choisir une cible à attaquer!");
- }
- else {
- const defender = target?.actor;
- const defenderTokenId = target?.id;
- if (defender.type == 'entite' && defender.system.definition.typeentite == ENTITE_NONINCARNE) {
- ui.notifications.warn("Vous ne pouvez pas cibler une entité non incarnée !!!!");
- } else {
- return this.create(attacker, defender, defenderTokenId, target)
- }
- }
+ static rddCombatTarget(attacker, target) {
+ const defender = target?.actor;
+ const defenderTokenId = target?.id;
+ return new RdDCombat(attacker, defender, defenderTokenId, target)
+ }
+
+ static isTargetEntite(target) {
+ return target?.actor.type == 'entite' && target?.actor.system.definition.typeentite == ENTITE_NONINCARNE;
}
/* -------------------------------------------- */
static getTarget() {
- if (game.user.targets && game.user.targets.size == 1) {
- for (let target of game.user.targets) {
- return target;
+ const targets = game.user.targets;
+ switch (targets?.size ?? 0) {
+ case 1:
+ for (let t of targets) {
+ return t;
+ }
+ default:
+ ui.notifications.warn("Vous devez choisir une cible (et une seule) à attaquer!");
+ return;
+ }
+ }
+
+ /* -------------------------------------------- */
+ static rddCombatForAttackerAndDefender(attackerId, defenderTokenId) {
+ const attacker = game.actors.get(attackerId);
+ let defender = defenderTokenId ? canvas.tokens.get(defenderTokenId)?.actor : undefined;
+ let target = undefined
+ if (!defenderTokenId || !defender) {
+ target = RdDCombat.getTarget()
+ if (!target) {
+ return;
+ }
+ defenderTokenId = target.id;
+ defender = target.actor;
+ if (!defenderTokenId || !defender) {
+ return;
}
}
- return undefined;
- }
-
- /* -------------------------------------------- */
- static create(attacker, defender, defenderTokenId, target = undefined) {
return new RdDCombat(attacker, defender, defenderTokenId, target)
}
- /* -------------------------------------------- */
- static createForAttackerAndDefender(attackerId, defenderTokenId) {
- const attacker = game.actors.get(attackerId);
- if (defenderTokenId) {
- const defenderToken = canvas.tokens.get(defenderTokenId);
- const defender = defenderToken.actor;
-
- return RdDCombat.create(attacker, defender, defenderTokenId);
- }
- return RdDCombat.createUsingTarget(attacker)
- }
-
/* -------------------------------------------- */
static onMsgEncaisser(msg) {
let defender = canvas.tokens.get(msg.defenderTokenId).actor;
@@ -523,7 +521,7 @@ export class RdDCombat {
let attacker = msg.attackerId ? game.actors.get(msg.attackerId) : undefined;
defender.encaisserDommages(attackerRoll, attacker);
- const rddCombat = RdDCombat.createForAttackerAndDefender(msg.attackerId, msg.defenderTokenId);
+ const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.defenderTokenId);
rddCombat?.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
}
}
@@ -532,7 +530,7 @@ export class RdDCombat {
static onMsgDefense(msg) {
let defenderToken = canvas.tokens.get(msg.defenderTokenId);
if (defenderToken && Misc.isUniqueConnectedGM()) {
- const rddCombat = RdDCombat.createForAttackerAndDefender(msg.attackerId, msg.defenderTokenId);
+ const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.defenderTokenId);
rddCombat?.removeChatMessageActionsPasseArme(msg.defenderRoll.passeArme);
rddCombat?._chatMessageDefense(msg.paramChatDefense, msg.defenderRoll);
}
@@ -559,11 +557,10 @@ export class RdDCombat {
'#echec-total-attaque',
]) {
html.on("click", button, event => {
- const rddCombat = RdDCombat.createForAttackerAndDefender(
+ const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(
event.currentTarget.attributes['data-attackerId']?.value,
event.currentTarget.attributes['data-defenderTokenId']?.value);
if (rddCombat) {
-
rddCombat.onEvent(button, event);
event.preventDefault();
}
diff --git a/module/rdd-possession.js b/module/rdd-possession.js
index 1683d435..1bda5b76 100644
--- a/module/rdd-possession.js
+++ b/module/rdd-possession.js
@@ -27,7 +27,133 @@ export class RdDPossession {
}
/* -------------------------------------------- */
- static updateEtatPossession(possession) {
+ static async onAttaquePossession(target, attacker, competence, possession = undefined) {
+ const defender = target.actor;
+ possession = duplicate(possession ?? this.searchPossessionFromEntite(attacker, defender) ?? (await this.createPossession(attacker, defender)));
+
+ this.$updateEtatPossession(possession)
+ let rollData = {
+ mode: "possession",
+ isECNIDefender: false,
+ competence: competence,
+ possession: possession,
+ attacker: attacker,
+ defender: defender
+ };
+ if (attacker.isCreature()) {
+ RdDItemCompetenceCreature.setRollDataCreature(rollData)
+ }
+
+ await RdDPossession.$rollAttaquePossession(attacker, rollData);
+ }
+
+ /* -------------------------------------------- */
+ static async onConjurerPossession(attacker, competence, possession) {
+ possession = duplicate(possession);
+ this.$updateEtatPossession(possession)
+ let rollData = {
+ mode: "possession",
+ isECNIDefender: true,
+ competence: competence,
+ possession: possession,
+ attacker: attacker,
+ defender: game.actors.get(possession.system.possesseurid)
+ };
+ await RdDPossession.$rollAttaquePossession(attacker, rollData);
+ }
+
+ /* -------------------------------------------- */
+ static async onDefensePossession(attackerId, defenderId, possessionId) {
+ let attacker = game.actors.get(attackerId)
+ let possession = attacker?.getPossession(possessionId)
+ defenderId = defenderId ?? possession?.system.possesseurid ?? undefined
+ let defender = game.actors.get(defenderId)
+ possession = possession ?? defender?.getPossession(possessionId) ?? undefined;
+
+ if (!possession) {
+ ui.notifications.warn("Une erreur s'est produite : Aucune possession trouvée !!")
+ return
+ }
+ // Update for draconic roll
+ let rollData = {
+ mode: "conjuration",
+ isECNIDefender: defender.type == "entite",
+ possession: duplicate(possession),
+ attacker: attacker,
+ defender: defender,
+ competence: defender.getDraconicOuPossession(),
+ selectedCarac: defender.system.carac.reve,
+ forceCarac: { 'reve-actuel': { label: "Rêve Actuel", value: defender.getReveActuel() } }
+ }
+ rollData.competence.system.defaut_carac = 'reve-actuel'
+
+ await RdDPossession.$rollDefensePossesion(defender, rollData);
+ }
+
+ /* -------------------------------------------- */
+ static async $rollAttaquePossession(attacker, rollData) {
+ const dialog = await RdDRoll.create(attacker, rollData,
+ {
+ html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html'
+ }, {
+ name: 'jet-possession',
+ label: rollData.isECNIDefender ? 'Conjurer la possession' : 'Possession',
+ callbacks: [
+ { condition: r => (r.rolled.isSuccess), action: async (r) => await this.$onRollPossession(r, true) },
+ { condition: r => (r.rolled.isEchec), action: async (r) => await this.$onRollPossession(r, false) },
+ ]
+ });
+ dialog.render(true);
+ }
+
+ /* -------------------------------------------- */
+ static async $rollDefensePossesion(defender, rollData) {
+ const dialog = await RdDRoll.create(defender, rollData,
+ {
+ html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-defense-possession.html'
+ },
+ {
+ name: 'conjurer',
+ label: 'Conjurer une Possession',
+ callbacks: [
+ { action: async (r) => await this.$onRollConjuration(r) }
+ ]
+ }
+ );
+ dialog.render(true);
+ }
+
+ /* -------------------------------------------- */
+ static async $onRollPossession(rollData, isSuccess) {
+ rollData.possession.isSuccess = isSuccess;
+ this.$updateEtatPossession(rollData.possession);
+ await RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-possession.html');
+ }
+
+ /* -------------------------------------------- */
+ static async $onRollConjuration(rollData) {
+ let actor = game.actors.get(rollData.possession.system.possedeid)
+ if (!rollData.rolled.isSuccess) {
+ if (rollData.isECNIDefender) {
+ rollData.possession.system.compteur--
+ } else {
+ rollData.possession.system.compteur++
+ }
+ let update = { _id: rollData.possession._id, "system.compteur": rollData.possession.system.compteur }
+ await actor.updateEmbeddedDocuments('Item', [update])
+ }
+
+ this.$updateEtatPossession(rollData.possession)
+
+ await RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-possession.html')
+ if (rollData.possession.isPosseder || rollData.possession.isConjurer) {
+ // conjuration
+ actor.deleteEmbeddedDocuments("Item", [rollData.possession._id])
+ }
+ }
+
+ /* -------------------------------------------- */
+ static $updateEtatPossession(possession) {
possession.ptsConjuration = 0
possession.ptsPossession = 0
console.log("Possession", possession)
@@ -47,111 +173,6 @@ export class RdDPossession {
}
}
- /* -------------------------------------------- */
- static async resultConjuration(rollData) {
- let actor = game.actors.get(rollData.possession.system.possedeid)
- if (!rollData.rolled.isSuccess) {
- if (rollData.isECNIDefender) {
- rollData.possession.system.compteur--
- } else {
- rollData.possession.system.compteur++
- }
- let update = { _id: rollData.possession._id, "system.compteur": rollData.possession.system.compteur }
- await actor.updateEmbeddedDocuments('Item', [update])
- }
-
- this.updateEtatPossession(rollData.possession)
- await RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-possession.html')
- if (rollData.possession.isPosseder || rollData.possession.isConjurer) {
- actor.deleteEmbeddedDocuments("Item", [rollData.possession._id])
- }
- }
-
- /* -------------------------------------------- */
- static async onDefensePossession(attackerId, defenderId, possessionId) {
- let attacker = game.actors.get(attackerId)
- let defender = game.actors.get(defenderId)
- let possession = attacker.getPossession(possessionId) ?? defender.getPossession(possessionId) ;
- if (!possession) {
- ui.notifications.warn("Une erreur s'est produite : Aucune possession trouvée !!")
- return
- }
- // Update for draconic roll
- let rollData = {
- mode: "conjuration",
- isECNIDefender: defender.type == "entite",
- possession: duplicate(possession),
- attacker: attacker,
- defender: defender,
- competence: defender.getDraconicOuPossession(),
- selectedCarac: defender.system.carac.reve,
- forceCarac: { 'reve-actuel': { label: "Rêve Actuel", value: defender.getReveActuel() } }
- }
- rollData.competence.system.defaut_carac = 'reve-actuel'
-
-
- const dialog = await RdDRoll.create(defender, rollData,
- {
- html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-defense-possession.html'
- },
- {
- name: 'conjurer',
- label: 'Conjurer une Possession',
- callbacks: [
- { action: async r => await this.resultConjuration(r) }
- ]
- }
- );
- dialog.render(true)
- }
-
- /* -------------------------------------------- */
- static async onAttaquePossession(attacker, competence, possession = undefined) {
- const target = RdDCombat.getTarget()
- if (target == undefined) {
- ui.notifications.warn((game.user.targets?.size ?? 0) > 1
- ? "Vous devez choisir une seule cible à posséder!"
- : "Vous devez choisir une cible à posséder!");
- return;
- }
-
- const defender = target.actor;
- possession = duplicate(possession ?? this.searchPossessionFromEntite(attacker, defender) ??(await this.createPossession(attacker, defender)));
-
- this.updateEtatPossession(possession)
- let rollData = {
- mode: "possession",
- isECNIDefender: defender.type == "entite",
- competence: competence,
- possession: possession,
- attacker: attacker,
- defender: defender
- };
- if (attacker.isCreature()) {
- RdDItemCompetenceCreature.setRollDataCreature(rollData)
- }
-
- const dialog = await RdDRoll.create(attacker, rollData,
- {
- html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html'
- }, {
- name: 'jet-possession',
- label: rollData.isECNIDefender ? 'Conjurer la possession' : 'Possession',
- callbacks: [
- { condition: r => (r.rolled.isSuccess), action: async r => await this._onRollPossession(r, true) },
- { condition: r => (r.rolled.isEchec), action: async r => await this._onRollPossession(r, false) },
- ]
- });
- dialog.render(true)
- }
-
- /* -------------------------------------------- */
- static async _onRollPossession(rollData, isSuccess) {
- rollData.possession.isSuccess = isSuccess;
- this.updateEtatPossession(rollData.possession);
- await RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-possession.html');
- }
-
/* -------------------------------------------- */
static async createPossession(attacker, defender) {
let possessionData = {
diff --git a/module/settings/regles-optionelles.js b/module/settings/regles-optionelles.js
index d9094180..6253b238 100644
--- a/module/settings/regles-optionelles.js
+++ b/module/settings/regles-optionelles.js
@@ -18,6 +18,7 @@ const listeReglesOptionelles = [
{ group: 'Règles générales', name: 'appliquer-fatigue', descr: "Appliquer les règles de fatigue"},
{ group: 'Règles générales', name: 'afficher-colonnes-reussite', descr: "Afficher le nombre de colonnes de réussite ou d'échec", default: false },
+ { group: 'Confirmations', name: 'confirmer-combat-sans-cible', descr: "Confirmer avant une attaque sans cible", scope: "client"},
{ group: 'Confirmations', name: 'confirmation-tmr', descr: "Confirmer pour monter dans les TMR", scope: "client"},
{ group: 'Confirmations', name: 'confirmation-refouler', descr: "Confirmer avant de refouler", scope: "client"},
{ group: 'Confirmations', name: 'confirmation-vider', descr: "Confirmer pour vider l'équipement", scope: "client"},