Fin de gestion encaissement/recul V2
This commit is contained in:
@@ -20,6 +20,10 @@
|
|||||||
- affichage du statut de surprise du défenseur
|
- affichage du statut de surprise du défenseur
|
||||||
- prise en compte des significatives (demi-surprises, armes disparates,
|
- prise en compte des significatives (demi-surprises, armes disparates,
|
||||||
particulière en finesse)
|
particulière en finesse)
|
||||||
|
- gestion de l'appel à la chance
|
||||||
|
- gestion de l'utilisation de la destinée
|
||||||
|
- gestion du recul depuis le messages
|
||||||
|
- gestion de l'encaissement depuis le messages
|
||||||
- impossible de faire un jet "actif" en surprise totale (attaque, parade, ...)
|
- impossible de faire un jet "actif" en surprise totale (attaque, parade, ...)
|
||||||
|
|
||||||
## 13.0.8 - Le renouveau d'Illysis
|
## 13.0.8 - Le renouveau d'Illysis
|
||||||
|
@@ -2682,6 +2682,17 @@ select,
|
|||||||
max-width: 1rem;
|
max-width: 1rem;
|
||||||
max-height: 1rem;
|
max-height: 1rem;
|
||||||
}
|
}
|
||||||
|
.system-foundryvtt-reve-de-dragon .chat-card-info {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
.system-foundryvtt-reve-de-dragon .chat-card-info img {
|
||||||
|
margin: 0 0.5rem;
|
||||||
|
max-width: 1rem;
|
||||||
|
max-height: 1rem;
|
||||||
|
filter: invert(0.8);
|
||||||
|
}
|
||||||
.system-foundryvtt-reve-de-dragon .chat-card-button {
|
.system-foundryvtt-reve-de-dragon .chat-card-button {
|
||||||
text-shadow: 1px 1px #4d3534;
|
text-shadow: 1px 1px #4d3534;
|
||||||
box-shadow: inset 1x 1px #a6827e;
|
box-shadow: inset 1x 1px #a6827e;
|
||||||
|
@@ -1963,6 +1963,18 @@
|
|||||||
max-height: 1rem;
|
max-height: 1rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.chat-card-info{
|
||||||
|
font-size: 1.1rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
img {
|
||||||
|
margin: 0 0.5rem;
|
||||||
|
max-width: 1rem;
|
||||||
|
max-height: 1rem;
|
||||||
|
filter: invert(0.8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.chat-card-button{
|
.chat-card-button{
|
||||||
text-shadow: 1px 1px #4d3534;
|
text-shadow: 1px 1px #4d3534;
|
||||||
|
@@ -506,7 +506,7 @@ export class RdDActor extends RdDBaseActorSang {
|
|||||||
'system.sante.fatigue.value': 0,
|
'system.sante.fatigue.value': 0,
|
||||||
'system.compteurs.ethylisme': { value: 1, nb_doses: 0, jet_moral: false }
|
'system.compteurs.ethylisme': { value: 1, nb_doses: 0, jet_moral: false }
|
||||||
})
|
})
|
||||||
await this.removeEffects(e => e.id != STATUSES.StatusDemiReve);
|
await this.removeEffects(e => !e.statuses?.has(STATUSES.StatusDemiReve));
|
||||||
await this.supprimerBlessures(it => true);
|
await this.supprimerBlessures(it => true);
|
||||||
await ChatMessage.create({
|
await ChatMessage.create({
|
||||||
whisper: ChatUtility.getOwners(this),
|
whisper: ChatUtility.getOwners(this),
|
||||||
@@ -2513,29 +2513,27 @@ export class RdDActor extends RdDBaseActorSang {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
async computeArmure(attackerRoll) {
|
async computeArmure(dmg) {
|
||||||
let dmg = (attackerRoll.dmg.dmgArme ?? 0) + (attackerRoll.dmg.dmgActor ?? 0);
|
let baseDmg = (dmg.dmgArme ?? 0) + (dmg.dmgActor ?? 0);
|
||||||
let armeData = attackerRoll.arme;
|
|
||||||
let protection = 0;
|
let protection = 0;
|
||||||
const armures = this.items.filter(it => it.type == "armure" && it.system.equipe);
|
if (dmg.encaisserSpecial != "noarmure") {
|
||||||
for (const armure of armures) {
|
const armures = this.items.filter(it => it.type == "armure" && it.system.equipe)
|
||||||
protection += await RdDDice.rollTotal(armure.system.protection.toString());
|
|
||||||
if (dmg > 0 && attackerRoll.dmg.encaisserSpecial != "noarmure") {
|
for (const armure of armures) {
|
||||||
await armure.deteriorerArmure(dmg)
|
protection += await RdDDice.rollTotal(armure.system.protection.toString());
|
||||||
dmg = 0;
|
if (baseDmg > 0 && dmg.encaisserSpecial != "noarmure") {
|
||||||
|
await armure.deteriorerArmure(baseDmg)
|
||||||
|
baseDmg = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protection -= Math.min(dmg.penetration, protection)
|
||||||
|
protection += this.getProtectionNaturelle();
|
||||||
|
// Gestion des cas particuliers sur la fenêtre d'encaissement
|
||||||
|
if (dmg.encaisserSpecial == "chute") {
|
||||||
|
protection = Math.min(protection, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const penetration = Misc.toInt(armeData?.system.penetration ?? 0);
|
console.log("Final protect", protection, dmg)
|
||||||
protection = Math.max(protection - penetration, 0);
|
|
||||||
protection += this.getProtectionNaturelle();
|
|
||||||
// Gestion des cas particuliers sur la fenêtre d'encaissement
|
|
||||||
if (attackerRoll.dmg.encaisserSpecial == "noarmure") {
|
|
||||||
protection = 0;
|
|
||||||
}
|
|
||||||
if (attackerRoll.dmg.encaisserSpecial == "chute") {
|
|
||||||
protection = Math.min(protection, 2);
|
|
||||||
}
|
|
||||||
console.log("Final protect", protection, attackerRoll);
|
|
||||||
return protection;
|
return protection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -118,8 +118,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
|||||||
.filter(it => it != undefined);
|
.filter(it => it != undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async computeArmure(dmg) { return this.getProtectionNaturelle() }
|
||||||
async computeArmure(attackerRoll) { return this.getProtectionNaturelle() }
|
|
||||||
async remiseANeuf() { }
|
async remiseANeuf() { }
|
||||||
async appliquerAjoutExperience(rollData, hideChatMessage = 'show') { }
|
async appliquerAjoutExperience(rollData, hideChatMessage = 'show') { }
|
||||||
|
|
||||||
@@ -227,12 +226,12 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
|||||||
isEffectAllowed(effectId) { return false }
|
isEffectAllowed(effectId) { return false }
|
||||||
|
|
||||||
getEffects(filter = e => true, forceRequise = undefined) {
|
getEffects(filter = e => true, forceRequise = undefined) {
|
||||||
const effects = this.getEmbeddedCollection("ActiveEffect").filter(filter)
|
const effects = this.getEmbeddedCollection("ActiveEffect")
|
||||||
|
const selected = effects.filter(filter)
|
||||||
if (forceRequise && this.isForceInsuffisante(forceRequise)) {
|
if (forceRequise && this.isForceInsuffisante(forceRequise)) {
|
||||||
/// TODO
|
selected.push(StatusEffects.prepareActiveEffect(STATUSES.StatusForceWeak))
|
||||||
effects.push(StatusEffects.prepareActiveEffect(STATUSES.StatusForceWeak))
|
|
||||||
}
|
}
|
||||||
return effects
|
return selected
|
||||||
}
|
}
|
||||||
|
|
||||||
getEffectByStatus(statusId) {
|
getEffectByStatus(statusId) {
|
||||||
@@ -257,7 +256,8 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
|||||||
|
|
||||||
async removeEffects(filter = e => true) {
|
async removeEffects(filter = e => true) {
|
||||||
if (game.user.isGM) {
|
if (game.user.isGM) {
|
||||||
const ids = this.getEffects(filter).map(it => it.id);
|
const effectsToRemove = this.getEffects(filter);
|
||||||
|
const ids = effectsToRemove.map(it => it.id);
|
||||||
await this.deleteEmbeddedDocuments('ActiveEffect', ids);
|
await this.deleteEmbeddedDocuments('ActiveEffect', ids);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -495,29 +495,37 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
async encaisser() { await RdDEncaisser.encaisser(this) }
|
async encaisser() { await RdDEncaisser.encaisser(this) }
|
||||||
|
|
||||||
async encaisserDommages(rollData, attacker = undefined, show = undefined, attackerToken = undefined, defenderToken = undefined) {
|
async encaisserDommages(dmg, attacker = undefined, show = undefined, attackerToken = undefined, defenderToken = undefined) {
|
||||||
if (attacker && !await attacker.accorder(this, 'avant-encaissement')) {
|
if (attacker && !await attacker.accorder(this, 'avant-encaissement')) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
const armure = await this.computeArmure(rollData);
|
if (!Misc.isOwnerPlayer(this)) {
|
||||||
|
return RdDBaseActor.remoteActorCall({
|
||||||
|
tokenId: attackerToken?.id ?? this.token?.id,
|
||||||
|
actorId: this.id,
|
||||||
|
method: 'encaisserDommages', args: [dmg, attacker, show, attackerToken, defenderToken]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const armure = await this.computeArmure(dmg)
|
||||||
if (ReglesOptionnelles.isUsing('validation-encaissement-gr')) {
|
if (ReglesOptionnelles.isUsing('validation-encaissement-gr')) {
|
||||||
await this.encaisserDommagesValidationGR(rollData, armure, show, attackerToken, defenderToken);
|
await this.encaisserDommagesValidationGR(dmg, armure, show, attackerToken, defenderToken);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const jet = await RdDUtility.jetEncaissement(this, rollData, armure, { showDice: SHOW_DICE });
|
const jet = await RdDUtility.jetEncaissement(this, dmg, armure, { showDice: SHOW_DICE });
|
||||||
await this.$onEncaissement(jet, show, attackerToken, defenderToken)
|
await this.$onEncaissement(jet, show, attackerToken, defenderToken)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async encaisserDommagesValidationGR(rollData, armure, show, attackerToken, defenderToken) {
|
async encaisserDommagesValidationGR(dmg, armure, show, attackerToken, defenderToken) {
|
||||||
if (!game.user.isGM) {
|
if (!game.user.isGM) {
|
||||||
RdDBaseActor.remoteActorCall({
|
RdDBaseActor.remoteActorCall({
|
||||||
tokenId: this.token?.id,
|
tokenId: this.token?.id,
|
||||||
actorId: this.id,
|
actorId: this.id,
|
||||||
method: 'encaisserDommagesValidationGR', args: [rollData, armure, show, attackerToken, defenderToken]
|
method: 'encaisserDommagesValidationGR', args: [dmg, armure, show, attackerToken, defenderToken]
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
DialogValidationEncaissement.validerEncaissement(this, rollData, armure,
|
DialogValidationEncaissement.validerEncaissement(this, dmg, armure,
|
||||||
jet => this.$onEncaissement(jet, show, attackerToken, defenderToken));
|
jet => this.$onEncaissement(jet, show, attackerToken, defenderToken));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -554,15 +562,37 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async encaisserRecul(force, dmgArme = 0) {
|
||||||
|
const diffRecul = this.getTaille() - force - dmgArme
|
||||||
|
const rolled = await RdDResolutionTable.roll(10, diffRecul)
|
||||||
|
if (rolled.isSuccess) {
|
||||||
|
return 'encaisse'
|
||||||
|
}
|
||||||
|
if (rolled.isETotal || (await this.rollEquilibre(diffRecul)).isEchec) {
|
||||||
|
await this.setEffect(STATUSES.StatusProne, true)
|
||||||
|
return 'chute'
|
||||||
|
}
|
||||||
|
return 'recul'
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
async rollEquilibre(diff) {
|
||||||
|
// TODO: accrobatie optionnelle sur jet d'équilibre?
|
||||||
|
if (ReglesOptionnelles.isSet('acrobatie-pour-recul')){
|
||||||
|
diff += Math.max(0, this.getCompetence('acrobatie')?.system.niveau ?? 0)
|
||||||
|
}
|
||||||
|
return await RdDResolutionTable.roll(this.getAgilite(), diff);
|
||||||
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
async accorder(entite, when = 'avant-encaissement') {
|
async accorder(entite, when = 'avant-encaissement') {
|
||||||
if (when != game.settings.get(SYSTEM_RDD, "accorder-entite-cauchemar")
|
if (when != game.settings.get(SYSTEM_RDD, "accorder-entite-cauchemar")
|
||||||
|| entite == undefined
|
|| entite == undefined
|
||||||
|| !entite.isEntite([ENTITE_INCARNE])
|
|| !entite.isEntite([ENTITE_INCARNE])
|
||||||
|| entite.isEntiteAccordee(this)) {
|
|| entite.isEntiteAccordee(this)) {
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
const rolled = await RdDResolutionTable.roll(this.getReveActuel(), - Number(entite.getNiveau()));
|
const rolled = await RdDResolutionTable.roll(this.getReveActuel(), - Number(entite.getNiveau()))
|
||||||
const rollData = {
|
const rollData = {
|
||||||
alias: this.getAlias(),
|
alias: this.getAlias(),
|
||||||
rolled: rolled,
|
rolled: rolled,
|
||||||
@@ -571,11 +601,11 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (rolled.isSuccess) {
|
if (rolled.isSuccess) {
|
||||||
await entite.setEntiteReveAccordee(this);
|
await entite.setEntiteReveAccordee(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
await RdDRollResult.displayRollData(rollData, this, 'chat-resultat-accorder-cauchemar.hbs');
|
await RdDRollResult.displayRollData(rollData, this, 'chat-resultat-accorder-cauchemar.hbs')
|
||||||
await this.appliquerAjoutExperience(rollData, true);
|
await this.appliquerAjoutExperience(rollData, true)
|
||||||
return rolled.isSuccess;
|
return rolled.isSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,6 +1,4 @@
|
|||||||
import { Grammar } from "../grammar.js";
|
|
||||||
import { ITEM_TYPES } from "../constants.js";
|
import { ITEM_TYPES } from "../constants.js";
|
||||||
import { LIST_CARAC_AUTRES } from "../rdd-carac.js";
|
|
||||||
import { RdDBaseActorSang } from "./base-actor-sang.js";
|
import { RdDBaseActorSang } from "./base-actor-sang.js";
|
||||||
|
|
||||||
export class RdDCreature extends RdDBaseActorSang {
|
export class RdDCreature extends RdDBaseActorSang {
|
||||||
@@ -45,5 +43,4 @@ export class RdDCreature extends RdDBaseActorSang {
|
|||||||
}
|
}
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -7,18 +7,17 @@ import { RdDUtility } from "./rdd-utility.js";
|
|||||||
*/
|
*/
|
||||||
export class DialogValidationEncaissement extends Dialog {
|
export class DialogValidationEncaissement extends Dialog {
|
||||||
|
|
||||||
static async validerEncaissement(actor, rollData, armure, onEncaisser) {
|
static async validerEncaissement(actor, dmg, armure, onEncaisser) {
|
||||||
const encaissement = await RdDUtility.jetEncaissement(actor, rollData, armure, { showDice: HIDE_DICE });
|
const encaissement = await RdDUtility.jetEncaissement(actor, dmg, armure, { showDice: HIDE_DICE });
|
||||||
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-validation-encaissement.hbs', {
|
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-validation-encaissement.hbs', {
|
||||||
actor: actor,
|
actor: actor,
|
||||||
rollData: rollData,
|
|
||||||
encaissement: encaissement
|
encaissement: encaissement
|
||||||
});
|
});
|
||||||
new DialogValidationEncaissement(html, actor, rollData, armure, encaissement, onEncaisser).render(true);
|
new DialogValidationEncaissement(html, actor, dmg, armure, encaissement, onEncaisser).render(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
constructor(html, actor, rollData, armure, encaissement, onEncaisser) {
|
constructor(html, actor, dmg, armure, encaissement, onEncaisser) {
|
||||||
// Common conf
|
// Common conf
|
||||||
let buttons = {
|
let buttons = {
|
||||||
"valider": { label: "Valider", callback: html => this.onValider() },
|
"valider": { label: "Valider", callback: html => this.onValider() },
|
||||||
@@ -42,11 +41,11 @@ export class DialogValidationEncaissement extends Dialog {
|
|||||||
super(dialogConf, dialogOptions);
|
super(dialogConf, dialogOptions);
|
||||||
|
|
||||||
this.actor = actor
|
this.actor = actor
|
||||||
this.rollData = rollData;
|
this.dmg = dmg
|
||||||
this.armure = armure;
|
this.armure = armure
|
||||||
this.encaissement = encaissement;
|
this.encaissement = encaissement
|
||||||
this.onEncaisser = onEncaisser;
|
this.onEncaisser = onEncaisser
|
||||||
this.forceDiceResult = {total: encaissement.roll.result };
|
this.forceDiceResult = {total: encaissement.roll.result }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@@ -55,14 +54,14 @@ export class DialogValidationEncaissement extends Dialog {
|
|||||||
this.html = html;
|
this.html = html;
|
||||||
this.html.find('input.encaissement-roll-result').keyup(async event => {
|
this.html.find('input.encaissement-roll-result').keyup(async event => {
|
||||||
this.forceDiceResult.total = event.currentTarget.value;
|
this.forceDiceResult.total = event.currentTarget.value;
|
||||||
this.encaissement = await RdDUtility.jetEncaissement(this.actor, this.rollData, this.armure, { showDice: HIDE_DICE, forceDiceResult: this.forceDiceResult});
|
this.encaissement = await RdDUtility.jetEncaissement(this.actor, this.dmg, this.armure, { showDice: HIDE_DICE, forceDiceResult: this.forceDiceResult});
|
||||||
this.html.find('label.encaissement-total').text(this.encaissement.total);
|
this.html.find('label.encaissement-total').text(this.encaissement.total);
|
||||||
this.html.find('label.encaissement-blessure').text(this.encaissement.blessures)
|
this.html.find('label.encaissement-blessure').text(this.encaissement.blessures)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async onValider() {
|
async onValider() {
|
||||||
this.encaissement = await RdDUtility.jetEncaissement(this.actor, this.rollData, this.armure, { showDice: SHOW_DICE, forceDiceResult: this.forceDiceResult});
|
this.encaissement = await RdDUtility.jetEncaissement(this.actor, this.dmg, this.armure, { showDice: SHOW_DICE, forceDiceResult: this.forceDiceResult});
|
||||||
this.onEncaisser(this.encaissement)
|
this.onEncaisser(this.encaissement)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
import { RdDItemArme } from "./item/arme.js";
|
import { RdDItemArme } from "./item/arme.js";
|
||||||
import { RdDPossession } from "./rdd-possession.js";
|
import { RdDPossession } from "./rdd-possession.js";
|
||||||
|
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
|
||||||
|
|
||||||
const conditionsTactiques = [
|
const conditionsTactiques = [
|
||||||
{ key: '', label: '', dmg: 0, attaque: 0, parade: 0, esquive: true, isTactique: false },
|
{ key: '', label: '', dmg: 0, attaque: 0, parade: 0, esquive: true, isTactique: false },
|
||||||
@@ -35,11 +36,14 @@ export class RdDBonus {
|
|||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static dmg(rollData, actor, isEntiteIncarnee = false) {
|
static dmg(rollData, actor, isEntiteIncarnee = false) {
|
||||||
|
const diff = rollData.diffLibre;
|
||||||
const dmgArme = RdDBonus.dmgArme(rollData.arme, rollData.arme?.system.dommagesReels)
|
const dmgArme = RdDBonus.dmgArme(rollData.arme, rollData.arme?.system.dommagesReels)
|
||||||
const forceRequise = rollData.arme ? RdDItemArme.valeurMain(rollData.arme.system.force ?? 0, RdDItemArme.getMainAttaque(rollData.competence)) : 0
|
const forceRequise = rollData.arme ? RdDItemArme.valeurMain(rollData.arme.system.force ?? 0, RdDItemArme.getMainAttaque(rollData.competence)) : 0
|
||||||
let dmg = {
|
let dmg = {
|
||||||
total: 0,
|
total: 0,
|
||||||
dmgArme: dmgArme,
|
dmgArme: dmgArme,
|
||||||
|
diff: diff,
|
||||||
|
dmgDiffLibre: ReglesOptionnelles.isUsing('degat-ajout-malus-libre') ? Math.abs(diff ?? 0) : 0,
|
||||||
penetration: RdDBonus._peneration(rollData),
|
penetration: RdDBonus._peneration(rollData),
|
||||||
dmgTactique: RdDBonus.dmgBonus(rollData.tactique),
|
dmgTactique: RdDBonus.dmgBonus(rollData.tactique),
|
||||||
dmgParticuliere: RdDBonus._dmgParticuliere(rollData),
|
dmgParticuliere: RdDBonus._dmgParticuliere(rollData),
|
||||||
@@ -51,6 +55,28 @@ export class RdDBonus {
|
|||||||
dmg.total = dmg.dmgSurprise + dmg.dmgTactique + dmg.dmgArme + dmg.dmgActor + dmg.dmgParticuliere + dmg.dmgForceInsuffisante
|
dmg.total = dmg.dmgSurprise + dmg.dmgTactique + dmg.dmgArme + dmg.dmgActor + dmg.dmgParticuliere + dmg.dmgForceInsuffisante
|
||||||
return dmg;
|
return dmg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static dmgRollV2(rollData, current) {
|
||||||
|
const actor = rollData.active.actor
|
||||||
|
const attaque = current.attaque
|
||||||
|
const arme = attaque.arme
|
||||||
|
const dmgArme = RdDBonus.dmgArme(arme, attaque.dommagesArme)
|
||||||
|
const dmg = {
|
||||||
|
total: 0,
|
||||||
|
dmgArme: dmgArme,
|
||||||
|
penetration: arme.penetration(),
|
||||||
|
diff: attaque.diff,
|
||||||
|
dmgTactique: current.tactique?.dmg ?? 0,
|
||||||
|
dmgParticuliere: 0, // TODO RdDBonus._dmgParticuliere(rollData),
|
||||||
|
dmgSurprise: rollData.opponent?.surprise?.dmg ?? 0,
|
||||||
|
mortalite: RdDBonus.mortalite(current.dmg?.mortalite, arme.system.mortalite, rollData.opponent?.actor?.isEntite()),
|
||||||
|
dmgActor: RdDBonus.bonusDmg(actor, attaque.carac.key, dmgArme, attaque.forceRequise),
|
||||||
|
dmgForceInsuffisante: Math.min(0, actor.getForce() - attaque.forceRequise),
|
||||||
|
dmgDiffLibre: ReglesOptionnelles.isUsing('degat-ajout-malus-libre') ? Math.abs(attaque.diff ?? 0) : 0
|
||||||
|
}
|
||||||
|
dmg.total = dmg.dmgSurprise + dmg.dmgTactique + dmg.dmgArme + dmg.dmgActor + dmg.dmgParticuliere + dmg.dmgForceInsuffisante + dmg.dmgDiffLibre
|
||||||
|
return dmg
|
||||||
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static description(condition) {
|
static description(condition) {
|
||||||
|
@@ -373,7 +373,7 @@ export class RdDCombat {
|
|||||||
if (Misc.isOwnerPlayer(defender)) {
|
if (Misc.isOwnerPlayer(defender)) {
|
||||||
let attackerRoll = msg.attackerRoll;
|
let attackerRoll = msg.attackerRoll;
|
||||||
let attacker = msg.attackerId ? game.actors.get(msg.attackerId) : undefined;
|
let attacker = msg.attackerId ? game.actors.get(msg.attackerId) : undefined;
|
||||||
defender.encaisserDommages(attackerRoll, attacker, msg.attackerToken);
|
defender.encaisserDommages(attackerRoll.dmg, attacker, msg.attackerToken);
|
||||||
const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.attackerToken.id, msg.defenderToken.id);
|
const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.attackerToken.id, msg.defenderToken.id);
|
||||||
rddCombat?.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
|
rddCombat?.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
|
||||||
}
|
}
|
||||||
@@ -982,21 +982,24 @@ export class RdDCombat {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async doRollDefense(rollData) {
|
async doRollDefense(rollData, callbacks = []) {
|
||||||
await RollDialog.create(rollData, {
|
await RollDialog.create(rollData, {
|
||||||
onRollDone: (dialog) => {
|
onRollDone: (dialog) => {
|
||||||
if (!OptionsAvancees.isUsing(ROLL_DIALOG_V2_TEST))
|
if (!OptionsAvancees.isUsing(ROLL_DIALOG_V2_TEST))
|
||||||
dialog.close()
|
dialog.close()
|
||||||
},
|
},
|
||||||
customChatMessage: true,
|
customChatMessage: true,
|
||||||
callbacks: [async (roll) => {
|
callbacks: [
|
||||||
this.removeChatMessageActionsPasseArme(roll.passeArme);
|
async (roll) => {
|
||||||
// defense: esquive / arme de parade / competence de défense
|
this.removeChatMessageActionsPasseArme(roll.passeArme);
|
||||||
if (!RdDCombat.isParticuliere(roll)) {
|
// defense: esquive / arme de parade / competence de défense
|
||||||
await roll.active.actor.incDecItemUse(roll.current[PART_DEFENSE].defense?.id);
|
if (!RdDCombat.isParticuliere(roll)) {
|
||||||
}
|
await roll.active.actor.incDecItemUse(roll.current[PART_DEFENSE].defense?.id);
|
||||||
await this._onDefense(roll);
|
}
|
||||||
}]
|
await this._onDefense(roll);
|
||||||
|
},
|
||||||
|
...callbacks
|
||||||
|
]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1027,12 +1030,10 @@ export class RdDCombat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async _onDefense(rollData) {
|
async _onDefense(rollData) {
|
||||||
console.log("RdDCombat._onDefense >>>", rollData)
|
|
||||||
const isEsquive = rollData.current[PART_DEFENSE].isEsquive
|
const isEsquive = rollData.current[PART_DEFENSE].isEsquive
|
||||||
const isParade = !isEsquive
|
const isParade = !isEsquive
|
||||||
if (RdDCombat.isReussite(rollData)) {
|
if (RdDCombat.isReussite(rollData)) {
|
||||||
if (isParade) {
|
if (isParade) {
|
||||||
await this.computeRecul(rollData)
|
|
||||||
await this.computeDeteriorationArme(rollData)
|
await this.computeDeteriorationArme(rollData)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1040,11 +1041,6 @@ export class RdDCombat {
|
|||||||
await this._onDefenseParticuliere(rollData, isEsquive)
|
await this._onDefenseParticuliere(rollData, isEsquive)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
//await this._sendMessageDefense(rollData.attackerRoll, rollData, { defense: true })
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: modify chat message
|
|
||||||
this.removeChatMessageActionsPasseArme(rollData.passeArme)
|
this.removeChatMessageActionsPasseArme(rollData.passeArme)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1269,44 +1265,14 @@ export class RdDCombat {
|
|||||||
}
|
}
|
||||||
const attackerRoll = defenderRoll.attackerRoll;
|
const attackerRoll = defenderRoll.attackerRoll;
|
||||||
if (this._isForceOuCharge(attackerRoll, defenderRoll.v2)) {
|
if (this._isForceOuCharge(attackerRoll, defenderRoll.v2)) {
|
||||||
const impact = this._computeImpactRecul(attackerRoll);
|
defenderRoll.show.recul = this.defender.encaisserRecul(this.attacker.getForce(), attackerRoll.dmg.dmgArme)
|
||||||
const rollRecul = await RdDResolutionTable.roll(10, impact)
|
|
||||||
defenderRoll.show.recul = await this.gererRecul(rollRecul, impact)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async gererRecul(rolled, impact) {
|
|
||||||
if (rolled.isSuccess) {
|
|
||||||
return 'encaisse'
|
|
||||||
}
|
|
||||||
if (rolled.isETotal || this._isReculCauseChute(impact)) {
|
|
||||||
|
|
||||||
await this.defender.setEffect(STATUSES.StatusProne, true)
|
|
||||||
return 'chute'
|
|
||||||
}
|
|
||||||
return 'recul'
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
async _isReculCauseChute(impact) {
|
|
||||||
const agilite = this.defender.getAgilite()
|
|
||||||
const chute = await RdDResolutionTable.rollData({ caracValue: agilite, finalLevel: impact })
|
|
||||||
return chute.rolled.isEchec
|
|
||||||
}
|
|
||||||
|
|
||||||
_isForceOuCharge(attaque, isRollV2 = false /* TODO: delete roll V1 */) {
|
_isForceOuCharge(attaque, isRollV2 = false /* TODO: delete roll V1 */) {
|
||||||
return attaque.particuliere == 'force' || 'charge' == (isRollV2 ? attaque.tactique?.key : attaque.tactique)
|
return attaque.particuliere == 'force' || 'charge' == (isRollV2 ? attaque.tactique?.key : attaque.tactique)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
_computeImpactRecul(attackerRoll) {
|
|
||||||
const taille = this.defender.getTaille()
|
|
||||||
const force = this.attacker.getForce()
|
|
||||||
const dommages = attackerRoll.dmg /* TODO: delete roll V1 */
|
|
||||||
? attackerRoll.dmg.dmgArme
|
|
||||||
: attackerRoll.arme.system.dommagesReels ?? attaque.arme.system.dommages;
|
|
||||||
return taille - (force + dommages);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
async encaisser(attackerRoll, defenderRoll) {
|
async encaisser(attackerRoll, defenderRoll) {
|
||||||
@@ -1316,12 +1282,16 @@ export class RdDCombat {
|
|||||||
this._onEchecTotal(defenderRoll);
|
this._onEchecTotal(defenderRoll);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await this.doRollEncaissement(attackerRoll, defenderRoll);
|
||||||
|
this.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
|
||||||
|
}
|
||||||
|
|
||||||
|
async doRollEncaissement(attackerRoll, defenderRoll) {
|
||||||
if (Misc.isOwnerPlayer(this.defender)) {
|
if (Misc.isOwnerPlayer(this.defender)) {
|
||||||
attackerRoll.attackerId = this.attackerId;
|
attackerRoll.attackerId = this.attackerId;
|
||||||
attackerRoll.defenderTokenId = this.defenderToken.id;
|
attackerRoll.defenderTokenId = this.defenderToken.id;
|
||||||
|
|
||||||
await this.computeRecul(defenderRoll);
|
await this.computeRecul(defenderRoll);
|
||||||
await this.defender.encaisserDommages(attackerRoll, this.attacker, defenderRoll?.show, this.attackerToken, this.defenderToken);
|
await this.defender.encaisserDommages(attackerRoll.dmg, 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
|
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, {
|
game.socket.emit(SYSTEM_SOCKET_ID, {
|
||||||
@@ -1332,9 +1302,8 @@ export class RdDCombat {
|
|||||||
attackerToken: this.attackerToken,
|
attackerToken: this.attackerToken,
|
||||||
defenderToken: this.defenderToken
|
defenderToken: this.defenderToken
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
this.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
@@ -66,12 +66,11 @@ export class RdDEncaisser extends Dialog {
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
performEncaisser(mortalite) {
|
performEncaisser(mortalite) {
|
||||||
this.actor.encaisserDommages({
|
this.actor.encaisserDommages({
|
||||||
dmg: {
|
total: Number(this.modifier),
|
||||||
total: Number(this.modifier),
|
ajustement: Number(this.modifier),
|
||||||
ajustement: Number(this.modifier),
|
encaisserSpecial: this.encaisserSpecial,
|
||||||
encaisserSpecial: this.encaisserSpecial,
|
mortalite: mortalite,
|
||||||
mortalite: mortalite
|
penetration: 0
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -9,6 +9,7 @@ import { RdDResolutionTable } from "./rdd-resolution-table.js";
|
|||||||
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
|
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
|
||||||
import { Grammar } from "./grammar.js";
|
import { Grammar } from "./grammar.js";
|
||||||
import { ACTOR_TYPES } from "./constants.js";
|
import { ACTOR_TYPES } from "./constants.js";
|
||||||
|
import { RdDUtility } from "./rdd-utility.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extend the base Dialog entity to select roll parameters
|
* Extend the base Dialog entity to select roll parameters
|
||||||
|
@@ -610,35 +610,33 @@ export class RdDUtility {
|
|||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static async getLocalisation(type = 'personnage') {
|
static async getLocalisation(type = 'personnage') {
|
||||||
let result = await RdDDice.rollTotal("1d20");
|
const loc = { result: await RdDDice.rollTotal("1d20")};
|
||||||
let txt = ""
|
|
||||||
if (type == 'personnage') {
|
if (type == 'personnage') {
|
||||||
if (result <= 3) txt = "Jambe, genou, pied, jarret";
|
if (loc.result <= 3) loc.txt = "Jambe, genou, pied, jarret";
|
||||||
else if (result <= 7) txt = "Hanche, cuisse, fesse";
|
else if (loc.result <= 7) loc.txt = "Hanche, cuisse, fesse";
|
||||||
else if (result <= 9) txt = "Ventre, reins";
|
else if (loc.result <= 9) loc.txt = "Ventre, reins";
|
||||||
else if (result <= 12) txt = "Poitrine, dos";
|
else if (loc.result <= 12) loc.txt = "Poitrine, dos";
|
||||||
else if (result <= 14) txt = "Avant-bras, main, coude";
|
else if (loc.result <= 14) loc.txt = "Avant-bras, main, coude";
|
||||||
else if (result <= 18) txt = "Epaule, bras, omoplate";
|
else if (loc.result <= 18) loc.txt = "Epaule, bras, omoplate";
|
||||||
else if (result == 19) txt = "Tête";
|
else if (loc.result == 19) loc.txt = "Tête";
|
||||||
else if (result == 20) txt = "Tête (visage)";
|
else if (loc.result == 20) loc.txt = "Tête (visage)";
|
||||||
} else {
|
} else {
|
||||||
if (result <= 7) txt = "Jambes/Pattes";
|
if (loc.result <= 7) loc.txt = "Jambes/Pattes";
|
||||||
else if (result <= 18) txt = "Corps";
|
else if (loc.result <= 18) loc.txt = "Corps";
|
||||||
else if (result <= 20) txt = "Tête";
|
else if (loc.result <= 20) loc.txt = "Tête";
|
||||||
}
|
}
|
||||||
|
return loc
|
||||||
return { result: result, label: txt };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static async jetEncaissement(actor, rollData, armure, options = { showDice: HIDE_DICE }) {
|
static async jetEncaissement(actor, dmg, armure, options = { showDice: HIDE_DICE }) {
|
||||||
const diff = Math.abs(rollData.diffLibre);
|
const diff = Math.abs(dmg.diff)
|
||||||
let formula = RdDUtility.formuleEncaissement(diff, options)
|
const formula = RdDUtility.formuleEncaissement(diff, options)
|
||||||
const roll = await RdDDice.roll(formula, options);
|
const roll = await RdDDice.roll(formula, options);
|
||||||
|
|
||||||
RdDUtility.remplaceDeMinParDifficulte(roll, diff, options);
|
RdDUtility.remplaceDeMinParDifficulte(roll, diff, options);
|
||||||
|
|
||||||
return await RdDUtility.prepareEncaissement(actor, rollData, roll, armure);
|
return await RdDUtility.prepareEncaissement(actor, dmg, roll, armure);
|
||||||
}
|
}
|
||||||
|
|
||||||
static remplaceDeMinParDifficulte(roll, diff, options) {
|
static remplaceDeMinParDifficulte(roll, diff, options) {
|
||||||
@@ -661,7 +659,7 @@ export class RdDUtility {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static formuleEncaissement(diff, options) {
|
static formuleEncaissement(diff) {
|
||||||
// Chaque dé fait au minimum la difficulté libre
|
// Chaque dé fait au minimum la difficulté libre
|
||||||
if (ReglesOptionnelles.isUsing('degat-minimum-malus-libre')) {
|
if (ReglesOptionnelles.isUsing('degat-minimum-malus-libre')) {
|
||||||
return `2d10min${diff}`
|
return `2d10min${diff}`
|
||||||
@@ -670,25 +668,22 @@ export class RdDUtility {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static async prepareEncaissement(actor, rollData, roll, armure) {
|
static async prepareEncaissement(actor, dmg, roll, armure) {
|
||||||
// La difficulté d'ataque s'ajoute aux dégâts
|
const jetTotal = roll.total + dmg.total - armure
|
||||||
const bonusDegatsDiffLibre = ReglesOptionnelles.isUsing('degat-ajout-malus-libre') ? Math.abs(rollData.diffLibre ?? 0) : 0
|
const encaissement = RdDUtility._selectEncaissement(jetTotal, dmg.mortalite);
|
||||||
const jetTotal = roll.total + rollData.dmg.total - armure + bonusDegatsDiffLibre
|
|
||||||
const encaissement = RdDUtility._selectEncaissement(jetTotal, rollData.dmg.mortalite);
|
|
||||||
const over20 = Math.max(jetTotal - 20, 0);
|
const over20 = Math.max(jetTotal - 20, 0);
|
||||||
encaissement.dmg = rollData.dmg
|
encaissement.dmg = dmg
|
||||||
if (ReglesOptionnelles.isUsing('localisation-aleatoire')) {
|
if (ReglesOptionnelles.isUsing('localisation-aleatoire')) {
|
||||||
encaissement.dmg.loc = rollData.dmg.loc ?? await RdDUtility.getLocalisation(actor.type)
|
encaissement.dmg.loc = dmg.loc ?? await RdDUtility.getLocalisation(actor.type)
|
||||||
encaissement.dmg.loc.label = encaissement.dmg.loc.label ?? 'Corps;'
|
encaissement.dmg.loc.label = encaissement.dmg.loc.label ?? 'Corps;'
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
encaissement.dmg.loc = { label: '' }
|
encaissement.dmg.loc = { label: '' }
|
||||||
}
|
}
|
||||||
encaissement.dmg.bonusDegatsDiffLibre = bonusDegatsDiffLibre
|
encaissement.roll = roll
|
||||||
encaissement.roll = roll;
|
encaissement.armure = armure
|
||||||
encaissement.armure = armure;
|
encaissement.penetration = dmg.penetration
|
||||||
encaissement.penetration = rollData.arme?.system.penetration ?? 0;
|
encaissement.total = jetTotal
|
||||||
encaissement.total = jetTotal;
|
|
||||||
encaissement.vie = await RdDUtility._evaluatePerte(encaissement.vie, over20);
|
encaissement.vie = await RdDUtility._evaluatePerte(encaissement.vie, over20);
|
||||||
encaissement.endurance = await RdDUtility._evaluatePerte(encaissement.endurance, over20);
|
encaissement.endurance = await RdDUtility._evaluatePerte(encaissement.endurance, over20);
|
||||||
return encaissement;
|
return encaissement;
|
||||||
|
@@ -37,10 +37,12 @@ export default class ChatRollResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
prepareDisplay(roll) {
|
prepareDisplay(roll) {
|
||||||
|
roll.done = roll.done || {}
|
||||||
roll.show = roll.show || {}
|
roll.show = roll.show || {}
|
||||||
roll.show.chance = this.isAppelChancePossible(roll)
|
roll.show.chance = this.isAppelChancePossible(roll)
|
||||||
roll.show.encaissement = this.isShowEncaissement(roll)
|
roll.show.encaissement = this.isShowEncaissement(roll)
|
||||||
roll.show.recul = this.isShowReculChoc(roll)
|
roll.show.recul = this.getReculChoc(roll)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isAppelChancePossible(roll) {
|
isAppelChancePossible(roll) {
|
||||||
@@ -54,11 +56,22 @@ export default class ChatRollResult {
|
|||||||
roll.attackerRoll?.dmg.mortalite != 'empoignade'
|
roll.attackerRoll?.dmg.mortalite != 'empoignade'
|
||||||
}
|
}
|
||||||
|
|
||||||
isShowReculChoc(roll) {
|
getReculChoc(roll, defender = roll.active.actor, attacker = roll.opponent.actor) {
|
||||||
const attaque = roll.attackerRoll
|
const attaque = roll.attackerRoll
|
||||||
return attaque &&
|
if (attaque &&
|
||||||
(roll.rolled.isEchec || !roll.current.defense.isEsquive) &&
|
(roll.rolled.isEchec || !roll.current.defense.isEsquive) &&
|
||||||
(attaque.particuliere == 'force' || 'charge' == attaque.tactique?.key)
|
(attaque.particuliere == 'force' || 'charge' == attaque.tactique?.key)) {
|
||||||
|
const taille = defender.system.carac.taille.value
|
||||||
|
const impact = attacker.system.carac.force.value + roll.attackerRoll?.dmg.dmgArme
|
||||||
|
return {
|
||||||
|
raison: 'charge' == attaque.tactique?.key ? 'charge' : 'particulière en force',
|
||||||
|
taille: taille,
|
||||||
|
impact: impact,
|
||||||
|
chances: RdDResolutionTable.computeChances(10, taille-impact).norm,
|
||||||
|
diff: taille - impact
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
async buildRollHtml(roll) {
|
async buildRollHtml(roll) {
|
||||||
@@ -69,6 +82,28 @@ export default class ChatRollResult {
|
|||||||
async chatListeners(html) {
|
async chatListeners(html) {
|
||||||
$(html).on("click", '.appel-chance', event => this.onClickAppelChance(event))
|
$(html).on("click", '.appel-chance', event => this.onClickAppelChance(event))
|
||||||
$(html).on("click", '.appel-destinee', event => this.onClickAppelDestinee(event))
|
$(html).on("click", '.appel-destinee', event => this.onClickAppelDestinee(event))
|
||||||
|
$(html).on("click", '.encaissement', event => this.onClickEncaissement(event))
|
||||||
|
$(html).on("click", '.resister-recul', event => this.onClickRecul(event))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
getCombat(roll) {
|
||||||
|
switch (roll.type.current) {
|
||||||
|
case ROLL_TYPE_DEFENSE:
|
||||||
|
return RdDCombat.rddCombatForAttackerAndDefender(roll.ids.opponentId, roll.ids.opponentTokenId, roll.ids.actorTokenId)
|
||||||
|
case ROLL_TYPE_ATTAQUE:
|
||||||
|
return RdDCombat.rddCombatForAttackerAndDefender(roll.ids.actorId, roll.ids.actorTokenId, roll.ids.opponentId)
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateChatMessage(chatMessage, savedRoll) {
|
||||||
|
ChatUtility.setMessageData(chatMessage, 'rollData', savedRoll)
|
||||||
|
const copy = foundry.utils.duplicate(savedRoll)
|
||||||
|
RollDialog.loadRollData(copy)
|
||||||
|
this.prepareDisplay(copy)
|
||||||
|
chatMessage.update({ content: await this.buildRollHtml(copy) })
|
||||||
|
chatMessage.render(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
onClickAppelChance(event) {
|
onClickAppelChance(event) {
|
||||||
@@ -81,32 +116,23 @@ export default class ChatRollResult {
|
|||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
}
|
}
|
||||||
|
|
||||||
getCombat(roll) {
|
|
||||||
switch (roll.type.current) {
|
|
||||||
case ROLL_TYPE_DEFENSE:
|
|
||||||
return RdDCombat.rddCombatForAttackerAndDefender(roll.ids.opponentId, roll.ids.opponentTokenId, roll.ids.actorId)
|
|
||||||
case ROLL_TYPE_ATTAQUE:
|
|
||||||
return RdDCombat.rddCombatForAttackerAndDefender(roll.ids.actorId, roll.ids.actorTokenId, roll.ids.opponentId)
|
|
||||||
}
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
onAppelChanceSuccess(savedRoll, chatMessage) {
|
onAppelChanceSuccess(savedRoll, chatMessage) {
|
||||||
const reRoll = foundry.utils.duplicate(savedRoll)
|
const reRoll = foundry.utils.duplicate(savedRoll)
|
||||||
reRoll.type.retry = true
|
reRoll.type.retry = true
|
||||||
|
const callbacks = [r => ChatUtility.removeChatMessageId(chatMessage.id)]
|
||||||
// TODO: annuler les effets
|
// TODO: annuler les effets
|
||||||
switch (reRoll.type.current) {
|
switch (reRoll.type.current) {
|
||||||
case ROLL_TYPE_DEFENSE:
|
case ROLL_TYPE_DEFENSE:
|
||||||
this.getCombat(reRoll)?.doRollDefense(reRoll)
|
this.getCombat(reRoll)?.doRollDefense(reRoll, callbacks)
|
||||||
break
|
break
|
||||||
case ROLL_TYPE_ATTAQUE:
|
case ROLL_TYPE_ATTAQUE:
|
||||||
this.getCombat(reRoll)?.doRollAttaque(reRoll)
|
// TODO
|
||||||
|
this.getCombat(reRoll)?.doRollAttaque(reRoll, callbacks)
|
||||||
break
|
break
|
||||||
default: {
|
default: {
|
||||||
RollDialog.create(reRoll)
|
RollDialog.create(reRoll, { callbacks: callbacks })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ChatUtility.removeChatMessageId(chatMessage.id)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async onAppelChanceEchec(savedRoll, chatMessage) {
|
async onAppelChanceEchec(savedRoll, chatMessage) {
|
||||||
@@ -114,15 +140,6 @@ export default class ChatRollResult {
|
|||||||
await this.updateChatMessage(chatMessage, savedRoll)
|
await this.updateChatMessage(chatMessage, savedRoll)
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateChatMessage(chatMessage, savedRoll) {
|
|
||||||
ChatUtility.setMessageData(chatMessage, 'rollData', savedRoll)
|
|
||||||
const copy = foundry.utils.duplicate(savedRoll)
|
|
||||||
RollDialog.loadRollData(copy)
|
|
||||||
this.prepareDisplay(copy)
|
|
||||||
chatMessage.update({ content: await this.buildRollHtml(copy) })
|
|
||||||
chatMessage.render(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
onClickAppelDestinee(event) {
|
onClickAppelDestinee(event) {
|
||||||
const chatMessage = ChatUtility.getChatMessage(event)
|
const chatMessage = ChatUtility.getChatMessage(event)
|
||||||
const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData')
|
const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData')
|
||||||
@@ -132,10 +149,32 @@ export default class ChatRollResult {
|
|||||||
const reRoll = foundry.utils.duplicate(savedRoll)
|
const reRoll = foundry.utils.duplicate(savedRoll)
|
||||||
reRoll.type.retry = true
|
reRoll.type.retry = true
|
||||||
RdDResolutionTable.significativeRequise(reRoll.rolled)
|
RdDResolutionTable.significativeRequise(reRoll.rolled)
|
||||||
await this.updateChatMessage(chatMessage, savedRoll)
|
await this.updateChatMessage(chatMessage, reRoll)
|
||||||
})
|
})
|
||||||
event.preventDefault()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async onClickEncaissement(event) {
|
||||||
|
const chatMessage = ChatUtility.getChatMessage(event)
|
||||||
|
const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData')
|
||||||
|
const attaque = savedRoll.attackerRoll
|
||||||
|
const defender = game.actors.get(savedRoll.ids.actorId)
|
||||||
|
const attacker = game.actors.get(savedRoll.ids.opponentId)
|
||||||
|
const defenderToken = savedRoll.ids.actorTokenId ? canvas.tokens.get(savedRoll.ids.actorTokenId) : undefined
|
||||||
|
const attackerToken = savedRoll.ids.opponentTokenId ? canvas.tokens.get(savedRoll.ids.opponentTokenId) : undefined
|
||||||
|
await defender?.encaisserDommages(attaque.dmg, attacker, undefined, attackerToken, defenderToken)
|
||||||
|
|
||||||
|
savedRoll.done.encaissement = true
|
||||||
|
await this.updateChatMessage(chatMessage, savedRoll)
|
||||||
|
}
|
||||||
|
|
||||||
|
async onClickRecul(event) {
|
||||||
|
const chatMessage = ChatUtility.getChatMessage(event)
|
||||||
|
const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData')
|
||||||
|
const defender = game.actors.get(savedRoll.ids.actorId)
|
||||||
|
const attacker = game.actors.get(savedRoll.ids.opponentId)
|
||||||
|
savedRoll.done.recul = await defender.encaisserRecul(attacker.getForce(), savedRoll.attackerRoll.dmg.dmgArme)
|
||||||
|
// const reculChoc = this.getReculChoc(savedRoll, defender, attacker)
|
||||||
|
await this.updateChatMessage(chatMessage, savedRoll)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@@ -288,6 +288,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
|
|||||||
target.attackerRoll = rollData.attackerRoll
|
target.attackerRoll = rollData.attackerRoll
|
||||||
target.rolled = rollData.rolled
|
target.rolled = rollData.rolled
|
||||||
target.result = rollData.result
|
target.result = rollData.result
|
||||||
|
target.done = target.done ?? {}
|
||||||
return target
|
return target
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
import { RdDBonus } from "../rdd-bonus.js"
|
import { RdDBonus } from "../rdd-bonus.js"
|
||||||
|
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js"
|
||||||
import { ROLL_TYPE_ATTAQUE } from "./roll-constants.mjs"
|
import { ROLL_TYPE_ATTAQUE } from "./roll-constants.mjs"
|
||||||
import { PART_CARAC } from "./roll-part-carac.mjs"
|
import { PART_CARAC } from "./roll-part-carac.mjs"
|
||||||
import { PART_COMP } from "./roll-part-comp.mjs"
|
import { PART_COMP } from "./roll-part-comp.mjs"
|
||||||
@@ -49,28 +50,7 @@ export class RollPartAttaque extends RollPartSelect {
|
|||||||
|
|
||||||
prepareContext(rollData) {
|
prepareContext(rollData) {
|
||||||
const current = this.getCurrent(rollData)
|
const current = this.getCurrent(rollData)
|
||||||
current.dmg = this.$dmgRollV2(rollData, current)
|
current.dmg = RdDBonus.dmgRollV2(rollData, current)
|
||||||
}
|
|
||||||
|
|
||||||
$dmgRollV2(rollData, current) {
|
|
||||||
const actor = rollData.active.actor
|
|
||||||
const attaque = current.attaque
|
|
||||||
const arme = attaque.arme
|
|
||||||
const dmgArme = RdDBonus.dmgArme(arme, attaque.dommagesArme)
|
|
||||||
|
|
||||||
const dmg = {
|
|
||||||
total: 0,
|
|
||||||
dmgArme: dmgArme,
|
|
||||||
penetration: arme.penetration(),
|
|
||||||
dmgTactique: current.tactique?.dmg ?? 0,
|
|
||||||
dmgParticuliere: 0, // TODO RdDBonus._dmgParticuliere(rollData),
|
|
||||||
dmgSurprise: rollData.opponent?.surprise?.dmg ?? 0,
|
|
||||||
mortalite: RdDBonus.mortalite(current.dmg?.mortalite, arme.system.mortalite, rollData.opponent?.actor?.isEntite()),
|
|
||||||
dmgActor: RdDBonus.bonusDmg(actor, attaque.carac.key, dmgArme, attaque.forceRequise),
|
|
||||||
dmgForceInsuffisante: Math.min(0, actor.getForce() - attaque.forceRequise)
|
|
||||||
}
|
|
||||||
dmg.total = dmg.dmgSurprise + dmg.dmgTactique + dmg.dmgArme + dmg.dmgActor + dmg.dmgParticuliere + dmg.dmgForceInsuffisante
|
|
||||||
return dmg
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getAjustements(rollData) {
|
getAjustements(rollData) {
|
||||||
|
@@ -13,6 +13,7 @@ const listeReglesOptionnelles = [
|
|||||||
|
|
||||||
{ group: 'Règles de combat', name: 'localisation-aleatoire', descr: "Proposer une localisation aléatoire des blessures" },
|
{ 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: 'recul', descr: "Appliquer le recul en cas de particulière en force ou de charge" },
|
||||||
|
{ group: 'Règles de combat', name: 'acrobatie-pour-recul', descr: "L'acrobatie aide à ne pas chuter en cas de recul" , default: false },
|
||||||
{ 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: '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" },
|
{ group: 'Règles de combat', name: 'deteriorationArmure', descr: "Tenir compte de la détérioration des armures" },
|
||||||
{ group: 'Règles de combat', name: 'defenseurDesarme', descr: "Le défenseur peut être désarmé en parant une particulière en force ou une charge avec une arme autre qu'un bouclier" },
|
{ group: 'Règles de combat', name: 'defenseurDesarme', descr: "Le défenseur peut être désarmé en parant une particulière en force ou une charge avec une arme autre qu'un bouclier" },
|
||||||
|
@@ -37,8 +37,8 @@
|
|||||||
{{#if encaissement.dmg.dmgSurprise}}
|
{{#if encaissement.dmg.dmgSurprise}}
|
||||||
<div>+dom surprise: {{plusMoins encaissement.dmg.dmgSurprise}}</div>
|
<div>+dom surprise: {{plusMoins encaissement.dmg.dmgSurprise}}</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if encaissement.dmg.bonusDegatsDiffLibre}}
|
{{#if encaissement.dmg.dmgDiffLibre}}
|
||||||
<div>+dom attaque: {{plusMoins encaissement.dmg.bonusDegatsDiffLibre}}</div>
|
<div>+dom attaque: {{plusMoins encaissement.dmg.dmgDiffLibre}}</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
|
@@ -1,12 +1,15 @@
|
|||||||
{{#if show.encaissement}}
|
{{#if show.encaissement}}
|
||||||
<a class='chat-card-button button-encaisser'
|
{{#if done.encaissement}}
|
||||||
{{!-- data-actorId='{{ids.actorId}}'
|
<span class='chat-card-info'>
|
||||||
data-actorTokenId='{{ids.actorTokenId}}'
|
<img src="systems/foundryvtt-reve-de-dragon/assets/ui/encaisser.svg"/>
|
||||||
data-opponentId='{{ids.opponentId}}'
|
{{active.name}} a encaissé
|
||||||
data-opponentTokenId='{{ids.opponentTokenId}}' --}}
|
</span>
|
||||||
data-tooltip="Encaisser à {{plusMoins attackerRoll.dmg.total}} {{#if (eq attackerRoll.dmg.mortalite 'non-mortel')~}}(non-mortel){{/if}}"
|
{{else}}
|
||||||
>
|
<a class='chat-card-button encaissement'
|
||||||
<img src="systems/foundryvtt-reve-de-dragon/assets/ui/encaisser.svg"/> Encaisser à {{plusMoins attackerRoll.dmg.total}}
|
data-tooltip="Encaisser à {{plusMoins attackerRoll.dmg.total}} {{#if (eq attackerRoll.dmg.mortalite 'non-mortel')~}}(non-mortel){{/if}}"
|
||||||
{{#if (eq attackerRoll.dmg.mortalite 'non-mortel')~}}(non-mortel){{/if}}
|
>
|
||||||
</a>
|
<img src="systems/foundryvtt-reve-de-dragon/assets/ui/encaisser.svg"/> Encaisser à {{plusMoins attackerRoll.dmg.total}}
|
||||||
|
{{#if (eq attackerRoll.dmg.mortalite 'non-mortel')~}}(non-mortel){{/if}}
|
||||||
|
</a>
|
||||||
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
@@ -1,11 +1,18 @@
|
|||||||
{{#if show.recul}}
|
{{#if show.recul}}
|
||||||
<a class='chat-card-button resister-recul-button'
|
{{#if (eq done.recul 'recul')}}
|
||||||
data-actorId='{{ids.actorId}}'
|
<span class='chat-card-info'>
|
||||||
data-actorTokenId='{{ids.actorTokenId}}'
|
<img src="systems/foundryvtt-reve-de-dragon/assets/ui/recul.svg"/>
|
||||||
data-opponentId='{{ids.opponentId}}'
|
{{active.name}} recule sous l'impact
|
||||||
data-opponentTokenId='{{ids.opponentTokenId}}'
|
</span>
|
||||||
data-tooltip="Résister au recul"
|
{{else if (eq done.recul 'chute')}}
|
||||||
>
|
<span class='chat-card-info'>
|
||||||
<img src="systems/foundryvtt-reve-de-dragon/assets/ui/recul.svg"/> Résister au recul
|
<img src="icons/svg/falling.svg"/>
|
||||||
</a>
|
{{active.name}} recule et chute sous l'impact
|
||||||
{{/if}}
|
</span>
|
||||||
|
{{else}}
|
||||||
|
<a class='chat-card-button resister-recul' data-tooltip="Résister au recul ({{show.recul.raison}}, taille {{show.recul.taille}}, impact {{show.recul.impact}})">
|
||||||
|
<img src="systems/foundryvtt-reve-de-dragon/assets/ui/recul.svg"/> Résister au recul
|
||||||
|
10 à {{plusMoins show.recul.diff}} = {{show.recul.chances}}%
|
||||||
|
</a>
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
Reference in New Issue
Block a user