Autoriser le combat sans cible
This commit is contained in:
parent
5424763ad6
commit
f57f03547a
@ -223,8 +223,18 @@ export class RdDActor extends Actor {
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getReveActuel() {
|
||||
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.iscombat && options.tryTarget) {
|
||||
const target = RdDCombat.getTarget();
|
||||
if (target) {
|
||||
if (rollData.competence.system.ispossession) {
|
||||
RdDPossession.onAttaquePossession(this, rollData.competence)
|
||||
return
|
||||
RdDPossession.onAttaquePossession(target, this, rollData.competence)
|
||||
}
|
||||
else if (RdDCombat.getTarget()) {
|
||||
const arme = RdDItemCompetenceCreature.toActionArme(rollData.competence)
|
||||
RdDCombat.createUsingTarget(this)?.attaque(competence, arme)
|
||||
return
|
||||
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)) {
|
||||
const target = RdDCombat.getTarget();
|
||||
if (!target) {
|
||||
RdDConfirm.confirmer({
|
||||
settingConfirmer: "confirmer-combat-sans-cible",
|
||||
content: `<p>Voulez vous faire un jet de compétence ${arme.system.competence} sans choisir de cible valide?
|
||||
<br>Tous les jets de combats devront être gérés à la main
|
||||
</p>`,
|
||||
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) {
|
||||
RdDPossession.onAttaquePossession(this, competence);
|
||||
} else {
|
||||
RdDCombat.createUsingTarget(this)?.attaque(competence, arme);
|
||||
}
|
||||
} else {
|
||||
this.rollCompetence(competence.name);
|
||||
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)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
@ -470,49 +470,47 @@ 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 <strong>une seule</strong> cible à attaquer!"
|
||||
: "Vous devez choisir une cible à attaquer!");
|
||||
}
|
||||
else {
|
||||
static rddCombatTarget(attacker, target) {
|
||||
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)
|
||||
}
|
||||
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 <strong>une seule</strong>) à attaquer!");
|
||||
return;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static create(attacker, defender, defenderTokenId, target = undefined) {
|
||||
return new RdDCombat(attacker, defender, defenderTokenId, target)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static createForAttackerAndDefender(attackerId, defenderTokenId) {
|
||||
static rddCombatForAttackerAndDefender(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);
|
||||
let defender = defenderTokenId ? canvas.tokens.get(defenderTokenId)?.actor : undefined;
|
||||
let target = undefined
|
||||
if (!defenderTokenId || !defender) {
|
||||
target = RdDCombat.getTarget()
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
return RdDCombat.createUsingTarget(attacker)
|
||||
defenderTokenId = target.id;
|
||||
defender = target.actor;
|
||||
if (!defenderTokenId || !defender) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
return new RdDCombat(attacker, defender, defenderTokenId, target)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -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();
|
||||
}
|
||||
|
@ -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 <strong>une seule</strong> 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 = {
|
||||
|
@ -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"},
|
||||
|
Loading…
Reference in New Issue
Block a user