Merge branch 'regles-combat' into 'v1.3'
Regles combat See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!133
This commit is contained in:
commit
12ecb702a4
@ -12,7 +12,7 @@ import { ChatUtility } from "./chat-utility.js";
|
|||||||
import { RdDItemSort } from "./item-sort.js";
|
import { RdDItemSort } from "./item-sort.js";
|
||||||
import { Grammar } from "./grammar.js";
|
import { Grammar } from "./grammar.js";
|
||||||
import { RdDEncaisser } from "./rdd-roll-encaisser.js";
|
import { RdDEncaisser } from "./rdd-roll-encaisser.js";
|
||||||
import { RdDCombat } from "./rdd-combat.js";
|
import { RdDCombat, RdDCombatSettings } from "./rdd-combat.js";
|
||||||
import { DeDraconique } from "./de-draconique.js";
|
import { DeDraconique } from "./de-draconique.js";
|
||||||
import { RdDAudio } from "./rdd-audio.js";
|
import { RdDAudio } from "./rdd-audio.js";
|
||||||
import { RdDItemCompetence } from "./item-competence.js";
|
import { RdDItemCompetence } from "./item-competence.js";
|
||||||
@ -32,6 +32,7 @@ export class RdDActor extends Actor {
|
|||||||
static init() {
|
static init() {
|
||||||
Hooks.on("deleteActiveEffect", (actor, effect, options) => actor.onDeleteActiveEffect(effect, options));
|
Hooks.on("deleteActiveEffect", (actor, effect, options) => actor.onDeleteActiveEffect(effect, options));
|
||||||
Hooks.on("createActiveEffect", (actor, effect, options) => actor.onCreateActiveEffect(effect, options));
|
Hooks.on("createActiveEffect", (actor, effect, options) => actor.onCreateActiveEffect(effect, options));
|
||||||
|
Hooks.on("updateActor", (actor, update, options, actorId) => actor.onUpdateActor(update, options, actorId));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@ -99,18 +100,18 @@ export class RdDActor extends Actor {
|
|||||||
// Make separate methods for each Actor type (character, npc, etc.) to keep
|
// Make separate methods for each Actor type (character, npc, etc.) to keep
|
||||||
// things organized.
|
// things organized.
|
||||||
if (actorData.type === 'personnage') this._prepareCharacterData(actorData);
|
if (actorData.type === 'personnage') this._prepareCharacterData(actorData);
|
||||||
if (actorData.type === 'creature') this.prepareCreatureData(actorData);
|
if (actorData.type === 'creature') this._prepareCreatureData(actorData);
|
||||||
if (actorData.type === 'vehicule') this.prepareVehiculeData(actorData);
|
if (actorData.type === 'vehicule') this._prepareVehiculeData(actorData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
prepareCreatureData(actorData) {
|
_prepareCreatureData(actorData) {
|
||||||
this.computeEncombrementTotalEtMalusArmure();
|
this.computeEncombrementTotalEtMalusArmure();
|
||||||
this.computeEtatGeneral();
|
this.computeEtatGeneral();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
prepareVehiculeData( actorData ) {
|
_prepareVehiculeData( actorData ) {
|
||||||
this.computeEncombrementTotalEtMalusArmure();
|
this.computeEncombrementTotalEtMalusArmure();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1105,7 +1106,7 @@ export class RdDActor extends Actor {
|
|||||||
if (this.isEntiteCauchemar()) {
|
if (this.isEntiteCauchemar()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return this.data.data.attributs?.sconst?.value ?? 0;
|
return RdDUtility.calculSConst(this.data.data.carac.constitution.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@ -1177,18 +1178,14 @@ export class RdDActor extends Actor {
|
|||||||
sonne: false,
|
sonne: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let minValue = 0;
|
let minValue = name == "vie" ? -this.getSConst()-1 : 0;
|
||||||
if (this.type == 'personnage') {
|
|
||||||
// TODO: les animaux/humanoïdes on théoriquement aussi un sconst, mais la SPA n'est pas passé par là
|
|
||||||
minValue = name == "vie" ? -Number(this.data.data.attributs.sconst.value) : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
result.newValue = Math.max(minValue, Math.min(compteur.value + inc, compteur.max));
|
result.newValue = Math.max(minValue, Math.min(compteur.value + inc, compteur.max));
|
||||||
//console.log("New value ", inc, minValue, result.newValue);
|
//console.log("New value ", inc, minValue, result.newValue);
|
||||||
let fatigue = 0;
|
let fatigue = 0;
|
||||||
if (name == "endurance" && this.data.type != 'entite') {
|
if (name == "endurance" && !this.isEntiteCauchemar()) {
|
||||||
if (!isCritique && result.newValue == 0 && inc < 0) { // perte endurance et endurance devient 0 -> -1 vie sauf si coup critique
|
if (result.newValue == 0 && inc < 0 && !isCritique) { // perte endurance et endurance devient 0 (sauf critique) -> -1 vie
|
||||||
sante.vie.value = sante.vie.value - 1;
|
sante.vie.value --;
|
||||||
}
|
}
|
||||||
result.newValue = Math.max(0, result.newValue);
|
result.newValue = Math.max(0, result.newValue);
|
||||||
if (inc > 0) { // le max d'endurance s'applique seulement à la récupération
|
if (inc > 0) { // le max d'endurance s'applique seulement à la récupération
|
||||||
@ -1202,6 +1199,7 @@ export class RdDActor extends Actor {
|
|||||||
result.jetEndurance = testIsSonne.roll.total;
|
result.jetEndurance = testIsSonne.roll.total;
|
||||||
} else if (inc > 0) {
|
} else if (inc > 0) {
|
||||||
await this.setSonne(false);
|
await this.setSonne(false);
|
||||||
|
sante.sonne.value = false;
|
||||||
}
|
}
|
||||||
if (sante.fatigue && inc < 0) { // Each endurance lost -> fatigue lost
|
if (sante.fatigue && inc < 0) { // Each endurance lost -> fatigue lost
|
||||||
fatigue = perte;
|
fatigue = perte;
|
||||||
@ -1213,6 +1211,9 @@ export class RdDActor extends Actor {
|
|||||||
if (sante.fatigue && fatigue > 0) {
|
if (sante.fatigue && fatigue > 0) {
|
||||||
sante.fatigue.value = Math.max(sante.fatigue.value + fatigue, this._computeFatigueMin());
|
sante.fatigue.value = Math.max(sante.fatigue.value + fatigue, this._computeFatigueMin());
|
||||||
}
|
}
|
||||||
|
if (!this.isEntiteCauchemar() && sante.vie.value<-this.getSConst()) {
|
||||||
|
await this.addStatusEffectById('dead');
|
||||||
|
}
|
||||||
|
|
||||||
await this.update({ "data.sante": sante });
|
await this.update({ "data.sante": sante });
|
||||||
return result;
|
return result;
|
||||||
@ -2221,6 +2222,9 @@ export class RdDActor extends Actor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_deteriorerArmure(item, dmg) {
|
_deteriorerArmure(item, dmg) {
|
||||||
|
if (!RdDCombatSettings.isUsingDeteriorationArmure()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let update = duplicate(item);
|
let update = duplicate(item);
|
||||||
update.data.deterioration = (update.data.deterioration ?? 0) + dmg;
|
update.data.deterioration = (update.data.deterioration ?? 0) + dmg;
|
||||||
if (update.data.deterioration >= 10) {
|
if (update.data.deterioration >= 10) {
|
||||||
@ -2366,8 +2370,11 @@ export class RdDActor extends Actor {
|
|||||||
count--;
|
count--;
|
||||||
} else {
|
} else {
|
||||||
// TODO: status effect dead
|
// TODO: status effect dead
|
||||||
ChatMessage.create({ content: `<strong>${this.name} vient de succomber à une seconde blessure critique ! Que les Dragons gardent son Archétype en paix !</strong>` });
|
this.addStatusEffectById('dead');
|
||||||
|
ChatMessage.create({ content: `<img class="chat-icon" src="icons/svg/skull.svg" alt="charge" height="32" width="32" />
|
||||||
|
<strong>${this.name} vient de succomber à une seconde blessure critique ! Que les Dragons gardent son Archétype en paix !</strong>` });
|
||||||
encaissement.critiques -= count;
|
encaissement.critiques -= count;
|
||||||
|
encaissement.mort = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2639,6 +2646,13 @@ export class RdDActor extends Actor {
|
|||||||
await this.update( { 'data.subacteurs.montures': newMontures });
|
await this.update( { 'data.subacteurs.montures': newMontures });
|
||||||
}
|
}
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
async onUpdateActor(update, options, actorId) {
|
||||||
|
const updatedEndurance = update?.data?.sante?.endurance;
|
||||||
|
if (updatedEndurance && options.diff) {
|
||||||
|
this.forceStatusEffectId('unconscious', updatedEndurance.value == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* -------------------------------------------- */
|
||||||
async onCreateActiveEffect(effect, options) {
|
async onCreateActiveEffect(effect, options) {
|
||||||
switch (StatusEffects.statusId(effect)) {
|
switch (StatusEffects.statusId(effect)) {
|
||||||
case 'sonne':
|
case 'sonne':
|
||||||
@ -2646,7 +2660,7 @@ export class RdDActor extends Actor {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
async onDeleteActiveEffect(effect, options) {
|
async onDeleteActiveEffect(effect, options) {
|
||||||
switch (StatusEffects.statusId(effect)) {
|
switch (StatusEffects.statusId(effect)) {
|
||||||
@ -2655,80 +2669,81 @@ export class RdDActor extends Actor {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
enleverTousLesEffets() {
|
enleverTousLesEffets() {
|
||||||
this.deleteEmbeddedEntity('ActiveEffect', Array.from(this.effects?.keys() ?? []));
|
this.deleteEmbeddedEntity('ActiveEffect', Array.from(this.effects?.keys() ?? []));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
listeEffets(matching = it => true) {
|
listeEffets(matching = it => true) {
|
||||||
const all = Array.from(this.effects?.values() ?? []);
|
const all = Array.from(this.effects?.values() ?? []);
|
||||||
const filtered = all.filter(it => matching(it.data));
|
const filtered = all.filter(it => matching(it.data));
|
||||||
return filtered;
|
return filtered;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
async setStatusDemiReve(status) {
|
async setStatusDemiReve(status) {
|
||||||
const options = { renderSheet: true/*, noHook: from == 'hook' */ };
|
|
||||||
if (status) {
|
if (status) {
|
||||||
await this.addEffect(StatusEffects.demiReve(), options)
|
await this.addStatusEffect(StatusEffects.demiReve())
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.deleteEffect(StatusEffects.demiReve(), options)
|
this.deleteStatusEffect(StatusEffects.demiReve())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
async setStatusSonne(sonne) {
|
async setStatusSonne(sonne) {
|
||||||
if (this.isEntiteCauchemar()) {
|
if (this.isEntiteCauchemar()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const id = 'sonne';
|
await this.forceStatusEffectId('sonne', sonne);
|
||||||
const options = { renderSheet: true/*, noHook: from == 'hook' */ };
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
async forceStatusEffectId(statusId, sonne) {
|
||||||
if (sonne) {
|
if (sonne) {
|
||||||
await this.addById(id, options);
|
await this.addStatusEffectById(statusId);
|
||||||
}
|
}
|
||||||
else /* if (!sonne)*/ {
|
else {
|
||||||
this.deleteById(id, options)
|
this.deleteStatusEffectById(statusId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
deleteById(id, options) {
|
deleteStatusEffectById(id, options = { renderSheet: true}) {
|
||||||
const effects = Array.from(this.effects?.values())
|
const effects = Array.from(this.effects?.values())
|
||||||
.filter(it => it.data.flags.core?.statusId == id);
|
.filter(it => it.data.flags.core?.statusId == id);
|
||||||
this._deleteAll(effects, options);
|
this._deleteStatusEffects(effects, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
deleteEffect(effect, options) {
|
deleteStatusEffect(effect, options = { renderSheet: true}) {
|
||||||
const toDelete = Array.from(this.effects?.values())
|
const toDelete = Array.from(this.effects?.values())
|
||||||
.filter(it => StatusEffects.statusId(it.data) == StatusEffects.statusId(effect));
|
.filter(it => StatusEffects.statusId(it.data) == StatusEffects.statusId(effect));
|
||||||
this._deleteAll(toDelete, options);
|
this._deleteStatusEffects(toDelete, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
_deleteAll(effects, options) {
|
_deleteStatusEffects(effects, options) {
|
||||||
this._deleteAllIds(effects.map(it => it.id), options);
|
this._deleteStatusEffectsByIds(effects.map(it => it.id), options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
_deleteAllIds(effectIds, options) {
|
_deleteStatusEffectsByIds(effectIds, options) {
|
||||||
this.deleteEmbeddedEntity('ActiveEffect', effectIds, options);
|
this.deleteEmbeddedEntity('ActiveEffect', effectIds, options);
|
||||||
this.applyActiveEffects();
|
this.applyActiveEffects();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
async addById(id, options) {
|
async addStatusEffectById(id, options = { renderSheet: true}) {
|
||||||
const statusEffect = CONFIG.statusEffects.find(it => it.id == id);
|
const statusEffect = CONFIG.statusEffects.find(it => it.id == id);
|
||||||
await this.addEffect(statusEffect, options);
|
await this.addStatusEffect(statusEffect, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
async addEffect(statusEffect, options) {
|
async addStatusEffect(statusEffect, options = { renderSheet: true}) {
|
||||||
this.deleteById(statusEffect.id, options);
|
this.deleteStatusEffectById(statusEffect.id, options);
|
||||||
const effet = duplicate(statusEffect);
|
const effet = duplicate(statusEffect);
|
||||||
effet["flags.core.statusId"] = effet.id;
|
effet["flags.core.statusId"] = effet.id;
|
||||||
await this.createEmbeddedEntity('ActiveEffect', effet, options);
|
await this.createEmbeddedEntity('ActiveEffect', effet, options);
|
||||||
|
@ -11,6 +11,7 @@ import { RdDRollTables } from "./rdd-rolltables.js";
|
|||||||
export class RdDCombat {
|
export class RdDCombat {
|
||||||
|
|
||||||
static init() {
|
static init() {
|
||||||
|
RdDCombatSettings.onInit();
|
||||||
this.initStorePasseArmes();
|
this.initStorePasseArmes();
|
||||||
Hooks.on("updateCombat", (combat, data) => { RdDCombat.onUpdateCombat(combat, data) });
|
Hooks.on("updateCombat", (combat, data) => { RdDCombat.onUpdateCombat(combat, data) });
|
||||||
Hooks.on("preDeleteCombat", (combat, options) => { RdDCombat.onPreDeleteCombat(combat, options); });
|
Hooks.on("preDeleteCombat", (combat, options) => { RdDCombat.onPreDeleteCombat(combat, options); });
|
||||||
@ -562,7 +563,7 @@ export class RdDCombat {
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
async choixParticuliere(rollData, choix) {
|
async choixParticuliere(rollData, choix) {
|
||||||
console.log("RdDCombat.choixParticuliere >>>", rollData, choix);
|
console.log("RdDCombat.choixParticuliere >>>", rollData, choix);
|
||||||
|
|
||||||
this.removeChatMessageActionsPasseArme(rollData.passeArme);
|
this.removeChatMessageActionsPasseArme(rollData.passeArme);
|
||||||
rollData.particuliere = choix;
|
rollData.particuliere = choix;
|
||||||
await this._onAttaqueNormale(rollData);
|
await this._onAttaqueNormale(rollData);
|
||||||
@ -594,7 +595,6 @@ export class RdDCombat {
|
|||||||
dialog.render(true);
|
dialog.render(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_prepareParade(attackerRoll, armeParade) {
|
_prepareParade(attackerRoll, armeParade) {
|
||||||
const compName = armeParade.data.competence;
|
const compName = armeParade.data.competence;
|
||||||
const armeAttaque = attackerRoll.arme;
|
const armeAttaque = attackerRoll.arme;
|
||||||
@ -606,7 +606,7 @@ export class RdDCombat {
|
|||||||
competence: this.defender.getCompetence(compName),
|
competence: this.defender.getCompetence(compName),
|
||||||
arme: armeParade,
|
arme: armeParade,
|
||||||
surprise: this.defender.getSurprise(true),
|
surprise: this.defender.getSurprise(true),
|
||||||
needParadeSignificative: RdDItemArme.needParadeSignificative(armeAttaque, armeParade),
|
needParadeSignificative: RdDCombatSettings.isUsingCategorieParade() && RdDItemArme.needParadeSignificative(armeAttaque, armeParade),
|
||||||
needResist: RdDItemArme.needArmeResist(armeAttaque, armeParade),
|
needResist: RdDItemArme.needArmeResist(armeAttaque, armeParade),
|
||||||
carac: this.defender.data.data.carac,
|
carac: this.defender.data.data.carac,
|
||||||
show: {}
|
show: {}
|
||||||
@ -632,6 +632,9 @@ export class RdDCombat {
|
|||||||
if (RdDBonus.isDefenseAttaqueFinesse(defenderRoll)) {
|
if (RdDBonus.isDefenseAttaqueFinesse(defenderRoll)) {
|
||||||
facteurSign *= 2;
|
facteurSign *= 2;
|
||||||
}
|
}
|
||||||
|
if (!RdDCombatSettings.isUsingTripleSignificative()) {
|
||||||
|
facteurSign = Math.min(facteurSign, 4);
|
||||||
|
}
|
||||||
return facteurSign;
|
return facteurSign;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -741,6 +744,9 @@ export class RdDCombat {
|
|||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
async computeDeteriorationArme(rollData) {
|
async computeDeteriorationArme(rollData) {
|
||||||
|
if (!RdDCombatSettings.isUsingResistanceArmeParade()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const attackerRoll = rollData.attackerRoll;
|
const attackerRoll = rollData.attackerRoll;
|
||||||
// Est-ce une parade normale?
|
// Est-ce une parade normale?
|
||||||
if (rollData.arme && attackerRoll && !rollData.rolled.isPart) {
|
if (rollData.arme && attackerRoll && !rollData.rolled.isPart) {
|
||||||
@ -772,7 +778,7 @@ export class RdDCombat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Si l'arme de parade n'est pas un bouclier, jet de désarmement (p.132)
|
// Si l'arme de parade n'est pas un bouclier, jet de désarmement (p.132)
|
||||||
if (resistance > 0 && RdDItemArme.getCategorieParade(rollData.arme) != 'boucliers') {
|
if (RdDCombatSettings.isUsingDefenseurDesarme() && resistance > 0 && RdDItemArme.getCategorieParade(rollData.arme) != 'boucliers') {
|
||||||
let desarme = await RdDResolutionTable.rollData({
|
let desarme = await RdDResolutionTable.rollData({
|
||||||
caracValue: this.defender.getForce(),
|
caracValue: this.defender.getForce(),
|
||||||
finalLevel: Misc.toInt(rollData.competence.data.niveau) - dmg,
|
finalLevel: Misc.toInt(rollData.competence.data.niveau) - dmg,
|
||||||
@ -783,31 +789,38 @@ export class RdDCombat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
async computeRecul(defenderRoll) { // Calcul du recul (p. 132)
|
async computeRecul(defenderRoll) { // Calcul du recul (p. 132)
|
||||||
const attackerRoll = defenderRoll.attackerRoll;
|
const attackerRoll = defenderRoll.attackerRoll;
|
||||||
if (this._isAttaqueCauseRecul(attackerRoll)) {
|
if (RdDCombatSettings.isUsingRecul() && this._isAttaqueCauseRecul(attackerRoll)) {
|
||||||
|
|
||||||
const impact = this._computeImpactRecul(attackerRoll);
|
const impact = this._computeImpactRecul(attackerRoll);
|
||||||
const rollRecul = await RdDResolutionTable.rollData({ caracValue: 10, finalLevel: impact });
|
const rollRecul = await RdDResolutionTable.rollData({ caracValue: 10, finalLevel: impact });
|
||||||
|
|
||||||
if (rollRecul.rolled.isSuccess) {
|
if (rollRecul.rolled.isSuccess) {
|
||||||
defenderRoll.show.recul = 'encaisse';
|
defenderRoll.show.recul = 'encaisse';
|
||||||
} else if (rollRecul.rolled.isETotal) {
|
} else if (rollRecul.rolled.isETotal || this._isReculCauseChute(impact)) {
|
||||||
defenderRoll.show.recul = 'chute';
|
defenderRoll.show.recul = 'chute';
|
||||||
|
await this.defender.addStatusEffectById('prone');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const agilite = this.defender.getAgilite();
|
defenderRoll.show.recul = 'recul';
|
||||||
const chute = await RdDResolutionTable.rollData({ caracValue: agilite, finalLevel: impact });
|
|
||||||
defenderRoll.show.recul = (chute.rolled.isSuccess) ? 'recul' : 'chute';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
async _isReculCauseChute(impact) {
|
||||||
|
const agilite = this.defender.getAgilite();
|
||||||
|
const chute = await RdDResolutionTable.rollData({ caracValue: agilite, finalLevel: impact });
|
||||||
|
return chute.rolled.isEchec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
_isAttaqueCauseRecul(attaque) {
|
_isAttaqueCauseRecul(attaque) {
|
||||||
return attaque.particuliere == 'force' || attaque.tactique == 'charge';
|
return attaque.particuliere == 'force' || attaque.tactique == 'charge';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
_computeImpactRecul(attaque) {
|
_computeImpactRecul(attaque) {
|
||||||
const taille = this.defender.getTaille();
|
const taille = this.defender.getTaille();
|
||||||
const force = this.attacker.getForce();
|
const force = this.attacker.getForce();
|
||||||
@ -902,5 +915,92 @@ export class RdDCombat {
|
|||||||
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-actor-turn-summary.html`, data)
|
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-actor-turn-summary.html`, data)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RdDCombatSettings extends FormApplication {
|
||||||
|
static onInit() {
|
||||||
|
game.settings.register("foundryvtt-reve-de-dragon", "rdd-combat-recul", { name: "rdd-combat-recul", scope: "world", config: false, default: true, type: Boolean });
|
||||||
|
game.settings.register("foundryvtt-reve-de-dragon", "rdd-combat-resistanceArmeParade", { name: "rdd-combat-resistanceArmeParade", scope: "world", config: false, default: true, type: Boolean });
|
||||||
|
game.settings.register("foundryvtt-reve-de-dragon", "rdd-combat-deteriorationArmure", { name: "rdd-combat-deteriorationArmure", scope: "world", config: false, default: true, type: Boolean });
|
||||||
|
game.settings.register("foundryvtt-reve-de-dragon", "rdd-combat-defenseurDesarme", { name: "rdd-combat-defenseurDesarme", scope: "world", config: false, default: true, type: Boolean });
|
||||||
|
game.settings.register("foundryvtt-reve-de-dragon", "rdd-combat-categorieParade", { name: "rdd-combat-categorieParade", scope: "world", config: false, default: true, type: Boolean });
|
||||||
|
game.settings.register("foundryvtt-reve-de-dragon", "rdd-combat-tripleSignificative", { name: "rdd-combat-tripleSignificative", scope: "world", config: false, default: true, type: Boolean });
|
||||||
|
|
||||||
|
game.settings.registerMenu("foundryvtt-reve-de-dragon", "rdd-combat-options", {
|
||||||
|
name: "Choisir les options de combat",
|
||||||
|
label: "Choix des options de combat",
|
||||||
|
hint: "Ouvre la fenêtre de sélection des options de combats pour désactiver certaines règles",
|
||||||
|
icon: "fas fa-bars",
|
||||||
|
type: RdDCombatSettings,
|
||||||
|
restricted: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(...args) {
|
||||||
|
super(...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
static get defaultOptions() {
|
||||||
|
const options = super.defaultOptions;
|
||||||
|
mergeObject(options, {
|
||||||
|
id: "combat-settings",
|
||||||
|
template: "systems/foundryvtt-reve-de-dragon/templates/combat-settings.html",
|
||||||
|
height: 600,
|
||||||
|
width: 350,
|
||||||
|
minimizable: false,
|
||||||
|
closeOnSubmit: true,
|
||||||
|
title: "Options de combat"
|
||||||
|
});
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
getData() {
|
||||||
|
let data = super.getData();
|
||||||
|
data.recul = RdDCombatSettings.isUsingRecul();
|
||||||
|
data.resistanceArmeParade = RdDCombatSettings.isUsingResistanceArmeParade();
|
||||||
|
data.deteriorationArmure = RdDCombatSettings.isUsingDeteriorationArmure();
|
||||||
|
data.defenseurDesarme = RdDCombatSettings.isUsingDefenseurDesarme();
|
||||||
|
data.categorieParade = RdDCombatSettings.isUsingCategorieParade();
|
||||||
|
data.tripleSignificative = RdDCombatSettings.isUsingTripleSignificative();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static isUsingRecul() {
|
||||||
|
return game.settings.get("foundryvtt-reve-de-dragon", "rdd-combat-recul");
|
||||||
|
}
|
||||||
|
|
||||||
|
static isUsingResistanceArmeParade() {
|
||||||
|
return game.settings.get("foundryvtt-reve-de-dragon", "rdd-combat-resistanceArmeParade");
|
||||||
|
}
|
||||||
|
|
||||||
|
static isUsingDeteriorationArmure() {
|
||||||
|
return game.settings.get("foundryvtt-reve-de-dragon", "rdd-combat-deteriorationArmure");
|
||||||
|
}
|
||||||
|
|
||||||
|
static isUsingDefenseurDesarme() {
|
||||||
|
return game.settings.get("foundryvtt-reve-de-dragon", "rdd-combat-defenseurDesarme");
|
||||||
|
}
|
||||||
|
|
||||||
|
static isUsingCategorieParade() {
|
||||||
|
return game.settings.get("foundryvtt-reve-de-dragon", "rdd-combat-categorieParade");
|
||||||
|
}
|
||||||
|
|
||||||
|
static isUsingTripleSignificative() {
|
||||||
|
return game.settings.get("foundryvtt-reve-de-dragon", "rdd-combat-tripleSignificative");
|
||||||
|
}
|
||||||
|
|
||||||
|
activateListeners(html) {
|
||||||
|
html.find(".select-option").click((event) => {
|
||||||
|
if (event.currentTarget.attributes.name) {
|
||||||
|
let id = event.currentTarget.attributes.name.value;
|
||||||
|
let isChecked = event.currentTarget.checked;
|
||||||
|
game.settings.set("foundryvtt-reve-de-dragon", id, isChecked);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async _updateObject(event, formData) {
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
|
@ -42,8 +42,6 @@ export class RdDRoll extends Dialog {
|
|||||||
finalLevel: 0,
|
finalLevel: 0,
|
||||||
diffConditions: 0,
|
diffConditions: 0,
|
||||||
diffLibre: rollData.competence?.data.default_diffLibre ?? 0,
|
diffLibre: rollData.competence?.data.default_diffLibre ?? 0,
|
||||||
editLibre: true,
|
|
||||||
editConditions: true,
|
|
||||||
malusArmureValue: actor.getMalusArmure(),
|
malusArmureValue: actor.getMalusArmure(),
|
||||||
surencMalusFlag: actor.isPersonnage() ? (actor.data.data.compteurs.surenc.value < 0) : false,
|
surencMalusFlag: actor.isPersonnage() ? (actor.data.data.compteurs.surenc.value < 0) : false,
|
||||||
surencMalusValue: actor.getSurenc(),
|
surencMalusValue: actor.getSurenc(),
|
||||||
|
@ -468,7 +468,7 @@ export class RdDUtility {
|
|||||||
let tailleData = tableCaracDerivee[bonusDomKey];
|
let tailleData = tableCaracDerivee[bonusDomKey];
|
||||||
data.attributs.plusdom.value = tailleData.plusdom;
|
data.attributs.plusdom.value = tailleData.plusdom;
|
||||||
|
|
||||||
data.attributs.sconst.value = tableCaracDerivee[Number(data.carac.constitution.value)].sconst;
|
data.attributs.sconst.value = RdDUtility.calculSConst(data.carac.constitution.value);
|
||||||
data.attributs.sust.value = tableCaracDerivee[Number(data.carac.taille.value)].sust;
|
data.attributs.sust.value = tableCaracDerivee[Number(data.carac.taille.value)].sust;
|
||||||
|
|
||||||
data.attributs.encombrement.value = (parseInt(data.carac.force.value) + parseInt(data.carac.taille.value)) / 2;
|
data.attributs.encombrement.value = (parseInt(data.carac.force.value) + parseInt(data.carac.taille.value)) / 2;
|
||||||
@ -489,6 +489,10 @@ export class RdDUtility {
|
|||||||
data.compteurs.chance.max = data.carac.chance.value;
|
data.compteurs.chance.max = data.carac.chance.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static calculSConst(constitution) {
|
||||||
|
return Number(tableCaracDerivee[Number(constitution)].sconst);
|
||||||
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static getSegmentsFatigue(maxEnd) {
|
static getSegmentsFatigue(maxEnd) {
|
||||||
maxEnd = Math.max(maxEnd, 1);
|
maxEnd = Math.max(maxEnd, 1);
|
||||||
|
@ -5,7 +5,7 @@ const rddStatusEffects = [
|
|||||||
demiReveStatusEffect
|
demiReveStatusEffect
|
||||||
];
|
];
|
||||||
const statusDemiSurprise = new Set(['sonne', 'prone', 'restrain']);
|
const statusDemiSurprise = new Set(['sonne', 'prone', 'restrain']);
|
||||||
const statusSurpriseTotale = new Set(['unconscious', 'blind']);
|
const statusSurpriseTotale = new Set(['unconscious', 'blind', 'dead']);
|
||||||
|
|
||||||
export class StatusEffects {
|
export class StatusEffects {
|
||||||
static onReady() {
|
static onReady() {
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
<li>
|
<li>
|
||||||
<label class="ctn-sonne">
|
<label class="ctn-sonne">
|
||||||
Sonné :
|
Sonné :
|
||||||
<input class="resource-content data-sante-sonne" type="checkbox" value="{{data.sante.sonne.value}}" {{#if data.sante.sonne.value}}checked{{/if}} />
|
<input class="resource-content data-sante-sonne" type="checkbox" {{#if data.sante.sonne.value}}checked{{/if}} />
|
||||||
</label>
|
</label>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
|
@ -20,13 +20,14 @@
|
|||||||
{{/unless}}
|
{{/unless}}
|
||||||
{{/unless}}, total: <span class="rdd-roll-echec">{{total}}</span>
|
{{/unless}}, total: <span class="rdd-roll-echec">{{total}}</span>
|
||||||
<br>
|
<br>
|
||||||
{{alias}} subit
|
{{alias}}
|
||||||
{{#if (eq dmg.mortalite 'cauchemar')}}le coup
|
{{#if (eq dmg.mortalite 'cauchemar')}}subit le coup
|
||||||
{{else if (gt eraflures 0)}}une contusion
|
{{else if eraflures}}subit une contusion
|
||||||
{{else if (gt legeres 0)}}une blessure légère
|
{{else if legeres}}subit une blessure légère
|
||||||
{{else if (gt graves 0)}}une blessure grave
|
{{else if graves}}subit une blessure grave
|
||||||
{{else if (gt critiques 0)}}une blessure critique
|
{{else if critiques}}subit une blessure critique
|
||||||
{{else}}Rien du tout
|
{{else if mort}}vient de mourir
|
||||||
|
{{else}}s'en sort sans une égratignure
|
||||||
{{/if}}
|
{{/if}}
|
||||||
({{dmg.loc.label}})
|
({{dmg.loc.label}})
|
||||||
{{#if (gt endurance 0)}}
|
{{#if (gt endurance 0)}}
|
||||||
|
28
templates/combat-settings.html
Normal file
28
templates/combat-settings.html
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<form autocomplete="off" onsubmit="event.preventDefault();">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<input class="select-option" type="checkbox" name="rdd-combat-recul" {{#if recul}}checked{{/if}}/>
|
||||||
|
<label>Appliquer le recul en cas de particulière en force ou de charge</label>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<input class="select-option" type="checkbox" name="rdd-combat-resistanceArmeParade" {{#if resistanceArmeParade}}checked{{/if}}/>
|
||||||
|
<label>Faire le jet de résistance des armes lors de parades pouvant les endommager</label>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<input class="select-option" type="checkbox" name="rdd-combat-deteriorationArmure" {{#if deteriorationArmure}}checked{{/if}}/>
|
||||||
|
<label>Tenir compte de la détérioration des armures</label>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<input class="select-option" type="checkbox" name="rdd-combat-defenseurDesarme" {{#if defenseurDesarme}}checked{{/if}}/>
|
||||||
|
<label>Le défenseur peut être désarmé en parant une particulière en force ou une charge avec une arme autre qu'un bouclier</label>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<input class="select-option" type="checkbox" name="rdd-combat-categorieParade" {{#if categorieParade}}checked{{/if}}/>
|
||||||
|
<label>Le défenseur doit obtenir une significative en cas de parade avec des armes de catégories différentes</label>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<input class="select-option" type="checkbox" name="rdd-combat-tripleSignificative" {{#if tripleSignificative}}checked{{/if}}/>
|
||||||
|
<label>En cas de demi-surprise, d'attaque particulière en finesse, et de catégories d'armes différentes, le défenseur doit obtenir 1/8 des chances de succès</label>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</form>
|
Loading…
Reference in New Issue
Block a user