diff --git a/module/actor-sheet.js b/module/actor-sheet.js
index 5f37c9c5..66ff36a1 100644
--- a/module/actor-sheet.js
+++ b/module/actor-sheet.js
@@ -14,6 +14,7 @@ import { MAINS_DIRECTRICES } from "./actor.js";
import { RdDBaseActorSheet } from "./actor/base-actor-sheet.js";
import { RdDItem } from "./item.js";
import { RdDItemBlessure } from "./item/blessure.js";
+import { RdDEmpoignade } from "./rdd-empoignade.js";
/* -------------------------------------------- */
/**
@@ -83,6 +84,7 @@ export class RdDActorSheet extends RdDBaseActorSheet {
RdDItemArme.ajoutCorpsACorps(formData.combat, formData.competences, formData.system.carac);
formData.esquives = this.actor.getCompetences("Esquive");
formData.combat = RdDCombatManager.listActionsArmes(formData.combat, formData.competences, formData.system.carac);
+ formData.empoignades = this.actor.getEmpoignades("Esquive");
this.armesList = formData.combat;
@@ -254,6 +256,11 @@ export class RdDActorSheet extends RdDBaseActorSheet {
this.actor.rollCarac('reve-actuel', true);
});
+ // Suite empoignade
+ this.html.find('.empoignade-label a').click(async event => {
+ let emp = RdDSheetUtility.getItem(event, this.actor)
+ RdDEmpoignade.onAttaqueEmpoignadeFromItem(emp)
+ });
// Roll Weapon1
this.html.find('.arme-label a').click(async event => {
let arme = this._getEventArmeCombat(event);
diff --git a/module/actor.js b/module/actor.js
index 3833f413..b4c90d44 100644
--- a/module/actor.js
+++ b/module/actor.js
@@ -36,6 +36,7 @@ import { RdDBaseActor } from "./actor/base-actor.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { RdDItemBlessure } from "./item/blessure.js";
import { AppAstrologie } from "./sommeil/app-astrologie.js";
+import { RdDEmpoignade } from "./rdd-empoignade.js";
const POSSESSION_SANS_DRACONIC = {
img: 'systems/foundryvtt-reve-de-dragon/icons/entites/possession.webp',
@@ -231,7 +232,6 @@ export class RdDActor extends RdDBaseActor {
getCompetences(name) {
return RdDItemCompetence.findCompetences(this.items, name)
}
-
/* -------------------------------------------- */
getTache(id) {
return this.findItemLike(id, 'tache');
@@ -286,7 +286,9 @@ export class RdDActor extends RdDBaseActor {
getPossessions() {
return this.items.filter(it => it.type == 'possession');
}
-
+ getEmpoignades() {
+ return this.items.filter(it => it.type == 'empoignade');
+ }
getDemiReve() {
return this.system.reve.tmrpos.coord;
}
@@ -329,8 +331,21 @@ export class RdDActor extends RdDBaseActor {
return '';
}
+ /* -------------------------------------------- */
+ hasArmeeMeleeEquipee() { // Return true si l'acteur possède au moins 1 arme de mêlée équipée
+ let melee = this.items.filter(it => it.type == "arme" && it.system.equipe && it.system.competence != "")
+ return (melee.length > 0)
+ }
+ isEmpoignadeEnCours() {
+ return this.items.find(it => it.type == "empoignade" && it.system.pointsemp > 0)
+ }
+
/* -------------------------------------------- */
async roll() {
+ if (this.isEmpoignadeEnCours()) {
+ ui.notifications.warn("Une empoignade est en cours ! Normalement, vous ne pouvez rien faire d'autre que continuer l'empoignade ou la rompre.")
+ }
+
const carac = mergeObject(duplicate(this.system.carac),
{
'reve-actuel': this.getCaracReveActuel(),
@@ -2061,6 +2076,10 @@ export class RdDActor extends RdDBaseActor {
/* -------------------------------------------- */
async rollUnSort(coord) {
+ if (this.isEmpoignadeEnCours()) {
+ ui.notifications.warn("Une empoignade est en cours ! Normalement, vous ne pouvez rien faire d'autre que continuer l'empoignade ou la rompre.")
+ }
+
if (EffetsDraconiques.isSortImpossible(this)) {
ui.notifications.error("Une queue ou un souffle vous empèche de lancer de sort!");
return;
@@ -2200,6 +2219,10 @@ export class RdDActor extends RdDBaseActor {
/* -------------------------------------------- */
async rollCarac(caracName, jetResistance = undefined) {
+ if (this.isEmpoignadeEnCours()) {
+ ui.notifications.warn("Une empoignade est en cours ! Normalement, vous ne pouvez rien faire d'autre que continuer l'empoignade ou la rompre.")
+ }
+
let selectedCarac = this.getCaracByName(caracName)
await this._openRollDialog({
name: 'jet-' + caracName,
@@ -2267,6 +2290,10 @@ export class RdDActor extends RdDBaseActor {
/* -------------------------------------------- */
async rollCompetence(idOrName, options = { tryTarget: true }) {
+ if (this.isEmpoignadeEnCours()) {
+ ui.notifications.warn("Une empoignade est en cours ! Normalement, vous ne pouvez rien faire d'autre que continuer l'empoignade ou la rompre.")
+ }
+
let rollData = {
carac: this.system.carac,
competence: this.getCompetence(idOrName)
@@ -2347,6 +2374,10 @@ export class RdDActor extends RdDBaseActor {
}
async rollCaracCompetence(caracName, compName, diff, options = { title: "" }) {
+ if (this.isEmpoignadeEnCours()) {
+ ui.notifications.warn("Une empoignade est en cours ! Normalement, vous ne pouvez rien faire d'autre que continuer l'empoignade ou la rompre.")
+ }
+
const competence = this.getCompetence(compName);
await this._openRollDialog({
name: 'jet-competence',
@@ -2367,6 +2398,10 @@ export class RdDActor extends RdDBaseActor {
/* -------------------------------------------- */
async rollTache(id, options = {}) {
+ if (this.isEmpoignadeEnCours()) {
+ ui.notifications.warn("Une empoignade est en cours ! Normalement, vous ne pouvez rien faire d'autre que continuer l'empoignade ou la rompre.")
+ }
+
const tacheData = this.getTache(id)
const compData = this.getCompetence(tacheData.system.competence)
compData.system.defaut_carac = tacheData.system.carac; // Patch !
@@ -3754,6 +3789,9 @@ export class RdDActor extends RdDBaseActor {
case 'casetmr':
await this.onDeleteOwnedCaseTmr(item, options, id);
break;
+ case 'empoignade':
+ await RdDEmpoignade.deleteLinkedEmpoignade(this.id, item)
+ break;
}
}
diff --git a/module/item-arme.js b/module/item-arme.js
index 4f78a8e4..a564e018 100644
--- a/module/item-arme.js
+++ b/module/item-arme.js
@@ -165,7 +165,7 @@ export class RdDItemArme extends Item {
let corpsACorps = competences.find(it => it.name == 'Corps à corps') ?? { system: { niveau: -6 } };
let init = RdDCombatManager.calculInitiative(corpsACorps.system.niveau, carac['melee'].value);
armes.push(RdDItemArme.mainsNues({ niveau: corpsACorps.system.niveau, initiative: init }));
- //armes.push(RdDItemArme.empoignade({ niveau: corpsACorps.system.niveau, initiative: init }));
+ armes.push(RdDItemArme.empoignade({ niveau: corpsACorps.system.niveau, initiative: init }));
}
static corpsACorps(mainsNuesActor) {
diff --git a/module/item.js b/module/item.js
index 3cd7b9c3..4fc78004 100644
--- a/module/item.js
+++ b/module/item.js
@@ -75,6 +75,7 @@ export const defaultItemImg = {
sortreserve: "systems/foundryvtt-reve-de-dragon/icons/competence_oniros.webp",
extraitpoetique: "systems/foundryvtt-reve-de-dragon/icons/competence_ecriture.webp",
tarot: "systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.webp",
+ empoignade: "systems/foundryvtt-reve-de-dragon/icons/competence_corps_a_corps.webp"
}
/* -------------------------------------------- */
diff --git a/module/rdd-bonus.js b/module/rdd-bonus.js
index 2516b0ff..2cf31e25 100644
--- a/module/rdd-bonus.js
+++ b/module/rdd-bonus.js
@@ -24,6 +24,9 @@ export class RdDBonus {
}
/* -------------------------------------------- */
static isDefenseAttaqueFinesse(rollData) {
+ if (rollData.isEmpoignade && rollData.rolled?.isPart) {
+ return true
+ }
return rollData.attackerRoll?.particuliere == 'finesse';
}
diff --git a/module/rdd-combat.js b/module/rdd-combat.js
index 8689e402..0851b208 100644
--- a/module/rdd-combat.js
+++ b/module/rdd-combat.js
@@ -12,6 +12,7 @@ import { RdDRollTables } from "./rdd-rolltables.js";
import { ReglesOptionelles } from "./settings/regles-optionelles.js";
import { STATUSES } from "./settings/status-effects.js";
import { Targets } from "./targets.js";
+import { RdDEmpoignade } from "./rdd-empoignade.js";
/* -------------------------------------------- */
const premierRoundInit = [
@@ -57,6 +58,7 @@ export class RdDCombatManager extends Combat {
ChatUtility.removeChatMessageContaining(`
`)
game.messages.filter(m => ChatUtility.getMessageData(m, 'attacker-roll') != undefined && ChatUtility.getMessageData(m, 'defender-roll') != undefined)
.forEach(it => it.delete());
+ RdDEmpoignade.deleteAllEmpoignades()
}
}
@@ -91,13 +93,26 @@ export class RdDCombatManager extends Combat {
}
} else {
const armeCombat = combatant.actor.itemTypes['arme'].find(it => it.system.equipe)
- const compName = (armeCombat == undefined) ? "Corps à corps" : armeCombat.system.competence;
+ let compName = "Corps à corps"
+ if (armeCombat) {
+ if (armeCombat.system.competence != "") {
+ compName = armeCombat.system.competence
+ }
+ if (armeCombat.system.lancer != "") {
+ compName = armeCombat.system.lancer
+ }
+ if (armeCombat.system.tir != "") {
+ compName = armeCombat.system.tir
+ }
+ }
const competence = RdDItemCompetence.findCompetence(combatant.actor.items, compName);
- if (competence) {
+ if (competence && competence.system.defaut_carac) {
const carac = combatant.actor.system.carac[competence.system.defaut_carac].value;
const niveau = competence.system.niveau;
const bonusEcaille = (armeCombat?.system.magique) ? armeCombat.system.ecaille_efficacite : 0;
rollFormula = RdDCombatManager.formuleInitiative(2, carac, niveau, bonusEcaille);
+ } else {
+ ui.notifications.warn(`Votre arme ${armeCombat.name} n'a pas de compétence renseignée`);
}
}
}
@@ -244,7 +259,7 @@ export class RdDCombatManager extends Combat {
} else if (actor.isPersonnage()) {
// Recupération des items 'arme'
const armes = actor.itemTypes['arme'].filter(it => RdDItemArme.isArmeUtilisable(it))
- //.concat(RdDItemArme.empoignade())
+ .concat(RdDItemArme.empoignade())
.concat(RdDItemArme.mainsNues());
const competences = actor.itemTypes['competence'];
@@ -737,17 +752,13 @@ export class RdDCombat {
if (!await this.attacker.accorder(this.defender, 'avant-attaque')) {
return;
}
- if (arme.system.cac == 'empoignade' && this.attacker.isCombatTouche()) {
- ChatMessage.create({
- alias: this.attacker.name,
- whisper: ChatUtility.getWhisperRecipientsAndGMs(this.attacker.name),
- content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-actor-perte-empoignade.html', {
- attacker: this.attacker,
- competence: competence
- })
- });
+ if (arme.system.cac == 'empoignade') {
+ RdDEmpoignade.onAttaqueEmpoignade(this.attacker, this.defender)
return;
}
+ if ( this.attacker.isEmpoignadeEnCours() ) {
+ ui.notifications.warn("Une empoignade est en cours ! Normalement, vous ne pouvez rien faire d'autre que continuer l'empoignade ou la rompre.")
+ }
let rollData = this._prepareAttaque(competence, arme);
console.log("RdDCombat.attaque >>>", rollData);
diff --git a/module/rdd-empoignade.js b/module/rdd-empoignade.js
new file mode 100644
index 00000000..605b6fee
--- /dev/null
+++ b/module/rdd-empoignade.js
@@ -0,0 +1,301 @@
+/* -------------------------------------------- */
+import { RdDCombat } from "./rdd-combat.js";
+import { RdDResolutionTable } from "./rdd-resolution-table.js";
+import { RdDRoll } from "./rdd-roll.js";
+import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
+import { ChatUtility } from "./chat-utility.js";
+import { STATUSES, StatusEffects } from "./settings/status-effects.js";
+
+/* -------------------------------------------- */
+
+/* -------------------------------------------- */
+export class RdDEmpoignade {
+
+ /* -------------------------------------------- */
+ static init() {
+ }
+
+ /* -------------------------------------------- */
+ static getEmpoignadeById(actor, id) {
+ let emp = actor.items.find(emp => emp.type == 'empoignade' && emp.system.empoignadeid == id)
+ return emp && duplicate(emp) || undefined;
+ }
+
+ /* -------------------------------------------- */
+ static getEmpoignade(attacker, defender) {
+ let emp = attacker.items.find(emp => emp.type == 'empoignade' && emp.system.empoigneurid == attacker.id && emp.system.empoigneid == defender.id)
+ if (!emp) {
+ emp = attacker.items.find(emp => emp.type == 'empoignade' && emp.system.empoigneurid == defender.id && emp.system.empoigneid == attacker.id)
+ }
+ if (emp) {
+ // TODO ? central storage ?
+ }
+ return emp && duplicate(emp) || undefined;
+ }
+ /* -------------------------------------------- */
+ static getMalusTaille(emp, attacker, defender) {
+ // Si pas empoigné, alors 0
+ if (emp.system.pointsemp == 0) {
+ return 0
+ }
+ // Malus de -1 si différence de taille de 2 ou plus (p 135)
+ if (attacker.system.carac.taille.value < defender.system.carac.taille.value - 1) {
+ return attacker.system.carac.taille.value - (defender.system.carac.taille.value - 1)
+ }
+ return 0
+ }
+
+ /* -------------------------------------------- */
+ static async onAttaqueEmpoignadeValidee(attacker, defender) {
+ let empoignade = RdDEmpoignade.getEmpoignade(attacker, defender)
+ const isNouvelle = empoignade == undefined;
+ empoignade = empoignade ?? (await RdDEmpoignade.createEmpoignade(attacker, defender))
+
+ let mode = (empoignade && empoignade.system.empoigneurid == attacker.id) ? "empoigner" : "liberer"
+
+ let rollData = {
+ mode: mode,
+ isEmpoignade: true,
+ competence: attacker.getCompetence("Corps à corps"),
+ selectedCarac: attacker.system.carac.melee,
+ empoignade: empoignade,
+ attackerId: attacker.id,
+ attackerName: attacker.name,
+ defenderName: defender.name,
+ defenderId: defender.id,
+ malusTaille: RdDEmpoignade.getMalusTaille(empoignade, attacker, defender)
+ }
+ if (attacker.isCreatureEntite()) {
+ RdDItemCompetenceCreature.setRollDataCreature(rollData)
+ }
+ if (empoignade.system.pointsemp >= 2) {
+ let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-actions.html');
+ ChatUtility.setMessageData(msg, "empoignade-roll-data", rollData)
+ } else {
+ await RdDEmpoignade.$rollAttaqueEmpoignade(attacker, rollData, isNouvelle);
+ }
+ }
+
+ /* -------------------------------------------- */
+ static async onAttaqueEmpoignade(attacker, defender) {
+ let empoignade = RdDEmpoignade.getEmpoignade(attacker, defender)
+ const isNouvelle = empoignade == undefined;
+ empoignade = empoignade ?? (await RdDEmpoignade.createEmpoignade(attacker, defender))
+ //console.log("W.", empoignade, defender.hasArmeeMeleeEquipee())
+ if ((isNouvelle || empoignade.system.pointsemp == 0) && defender.hasArmeeMeleeEquipee()) {
+ ChatUtility.createChatWithRollMode(attacker.name, {
+ content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-empoignade-valider.html`, { attacker: attacker, defender: defender })
+ })
+ } else {
+ await this.onAttaqueEmpoignadeValidee(attacker, defender)
+ }
+ }
+
+ /* -------------------------------------------- */
+ static async onAttaqueEmpoignadeFromItem(empoignade) {
+ let attacker = game.actors.get(empoignade.system.empoigneurid)
+ let defender = game.actors.get(empoignade.system.empoigneid)
+ await this.onAttaqueEmpoignadeValidee(attacker, defender)
+ }
+
+ /* -------------------------------------------- */
+ static async $rollAttaqueEmpoignade(attacker, rollData, isNouvelle = false) {
+ const dialog = await RdDRoll.create(attacker, rollData,
+ { html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html' },
+ {
+ name: 'jet-empoignade',
+ label: 'Empoigner',
+ callbacks: [
+ { condition: r => (r.rolled.isSuccess), action: async (r) => await RdDEmpoignade.$onRollEmpoignade(r, true, isNouvelle) },
+ { condition: r => (r.rolled.isEchec), action: async (r) => await RdDEmpoignade.$onRollEmpoignade(r, false, isNouvelle) },
+ ]
+ });
+ dialog.render(true);
+ }
+
+ /* -------------------------------------------- */
+ static async $onRollEmpoignade(rollData, isSuccess, isNouvelle = false) {
+ let attacker = game.actors.get(rollData.attackerId)
+ let defender = game.actors.get(rollData.defenderId)
+
+ let empoignade = rollData.empoignade
+ empoignade.isSuccess = isSuccess;
+
+ if (isSuccess && isNouvelle) {
+ // Creer l'empoignade sur attaquant/defenseur
+ await attacker.createEmbeddedDocuments('Item', [empoignade.toObject()])
+ await defender.createEmbeddedDocuments('Item', [empoignade.toObject()])
+ }
+ let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-resultat.html');
+ ChatUtility.setMessageData(msg, "empoignade-roll-data", rollData)
+ }
+
+ /* -------------------------------------------- */
+ static async onDefenseEmpoignade(rollData, defenseMode, competenceName = "Corps à corps", carac = "melee") {
+ let attacker = game.actors.get(rollData.attackerId)
+ let defender = game.actors.get(rollData.defenderId)
+ let empoignade = this.getEmpoignade(attacker, defender)
+
+ if (!empoignade) {
+ ui.notifications.warn("Une erreur s'est produite : Aucune empoignade trouvée !!")
+ return
+ }
+
+ empoignade = duplicate(empoignade)
+ rollData.mode = defenseMode
+ rollData.empoignade = empoignade
+ rollData.competence = defender.getCompetence(competenceName),
+ rollData.selectedCarac = defender.system.carac[carac],
+ rollData.malusTaille = RdDEmpoignade.getMalusTaille(empoignade, defender, attacker)
+
+ await RdDEmpoignade.$rollDefenseEmpoignade(defender, rollData);
+ }
+
+ /* -------------------------------------------- */
+ static async $rollDefenseEmpoignade(defender, rollData) {
+ const dialog = await RdDRoll.create(defender, rollData,
+ { html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-defense-empoignade.html' },
+ {
+ name: 'empoignade',
+ label: 'Contrer',
+ callbacks: [
+ { action: async (r) => await RdDEmpoignade.$onRollContrerLiberer(r) }
+ ]
+ }
+ );
+ dialog.render(true);
+ }
+
+ /* -------------------------------------------- */
+ static async $onRollContrerLiberer(rollData) {
+ let empoignade = rollData.empoignade
+
+ if (rollData.mode == "contrer-empoigner" && !rollData.rolled.isSuccess) {
+ empoignade.system.pointsemp++
+ RdDEmpoignade.$updateEtatEmpoignade(empoignade)
+ }
+ if (rollData.mode == "contrer-liberer" && !rollData.rolled.isSuccess) {
+ empoignade.system.pointsemp--
+ RdDEmpoignade.$updateEtatEmpoignade(empoignade)
+ }
+
+ if (empoignade.system.pointsemp >= 2) {
+ let attacker = game.actors.get(empoignade.system.empoigneurid)
+ let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-actions.html');
+ ChatUtility.setMessageData(msg, "empoignade-roll-data", rollData)
+ }
+ await RdDResolutionTable.displayRollData(rollData, rollData.defender, 'chat-empoignade-resultat.html')
+ }
+
+ /* -------------------------------------------- */
+ static async $updateEtatEmpoignade(empoignade) {
+ console.log("UPDATE Empoignade", empoignade)
+
+ let defender = game.actors.get(empoignade.system.empoigneid)
+ let emp = RdDEmpoignade.getEmpoignadeById(defender, empoignade.system.empoignadeid)
+ let update = { _id: emp._id, "system.pointsemp": empoignade.system.pointsemp, "system.ausol": empoignade.system.ausol }
+ await defender.updateEmbeddedDocuments('Item', [update])
+
+ let attacker = game.actors.get(empoignade.system.empoigneurid)
+ emp = RdDEmpoignade.getEmpoignadeById(attacker, empoignade.system.empoignadeid)
+ update = { _id: emp._id, "system.pointsemp": empoignade.system.pointsemp, "system.ausol": empoignade.system.ausol }
+ await attacker.updateEmbeddedDocuments('Item', [update])
+ }
+
+ /* -------------------------------------------- */
+ static async $deleteEmpoignade(empoignade) {
+ console.log("DELETE Empoignade", empoignade)
+
+ let defender = game.actors.get(empoignade.system.empoigneid)
+ let emp = RdDEmpoignade.getEmpoignadeById(defender, empoignade.system.empoignadeid)
+ await defender.deleteEmbeddedDocuments('Item', [emp._id])
+
+ let attacker = game.actors.get(empoignade.system.empoigneurid)
+ emp = RdDEmpoignade.getEmpoignadeById(attacker, empoignade.system.empoignadeid)
+ await attacker.deleteEmbeddedDocuments('Item', [emp._id])
+ }
+
+ /* -------------------------------------------- */
+ static async entrainerAuSol(rollData) {
+ let attacker = game.actors.get(rollData.attackerId)
+ let defender = game.actors.get(rollData.defenderId)
+ let empoignade = this.getEmpoignade(attacker, defender)
+
+ empoignade.system.ausol = true
+ await this.$updateEtatEmpoignade(empoignade)
+
+ await attacker.setEffect(STATUSES.StatusProne, true);
+ await defender.setEffect(STATUSES.StatusProne, true);
+
+ let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-entrainer-sol.html');
+ ChatUtility.setMessageData(msg, "empoignade-roll-data", rollData)
+ }
+
+ /* -------------------------------------------- */
+ static async projeterAuSol(rollData) {
+ let attacker = game.actors.get(rollData.attackerId)
+ let defender = game.actors.get(rollData.defenderId)
+ let empoignade = this.getEmpoignade(attacker, defender)
+
+ await defender.setEffect(STATUSES.StatusProne, true);
+ await this.$deleteEmpoignade(empoignade)
+
+ let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-projeter-sol.html');
+ ChatUtility.setMessageData(msg, "empoignade-roll-data", rollData)
+ }
+ /* -------------------------------------------- */
+ static async perteEndurance(rollData, perteMode) {
+ let attacker = game.actors.get(rollData.attackerId)
+ let defender = game.actors.get(rollData.defenderId)
+ let empoignade = this.getEmpoignade(attacker, defender)
+
+ console.log("Perte d'endurance :!!!", perteMode)
+ let endValue = defender.system.sante.endurance.value
+ if (perteMode == "end0") {
+ await defender.santeIncDec("endurance", -defender.system.sante.endurance.value);
+ }
+ if (perteMode == "end1") {
+ await defender.santeIncDec("endurance", -(defender.system.sante.endurance.value - 1));
+ }
+ if (perteMode == "endmoitie") {
+ await defender.santeIncDec("endurance", -Math.floor(defender.system.sante.endurance.value / 2));
+ }
+ if (perteMode == "endquart") {
+ await defender.santeIncDec("endurance", -(3 * Math.floor(defender.system.sante.endurance.value / 4)));
+ }
+ let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-perte-endurance.html');
+ ChatUtility.setMessageData(msg, "empoignade-roll-data", rollData)
+ }
+
+ /* -------------------------------------------- */
+ static async deleteAllEmpoignades() {
+ for (let actor of game.actors) {
+ let empList = actor.items.filter(it => it.type == "empoignade")
+ for (let emp of empList) {
+ await actor.deleteEmbeddedDocuments('Item', [emp.id])
+ }
+ }
+ }
+
+ /* -------------------------------------------- */
+ static async deleteLinkedEmpoignade(actorId, empoignade) {
+ let actorDeleteId = (actorId == empoignade.system.empoigneurid) ? empoignade.system.empoigneid : empoignade.system.empoigneurid
+ let actor = game.actors.get(actorDeleteId)
+ let emp = this.getEmpoignadeById(actor, empoignade.system.empoignadeid)
+ if (emp) {
+ await actor.deleteEmbeddedDocuments('Item', [emp._id])
+ }
+ }
+
+ /* -------------------------------------------- */
+ static async createEmpoignade(attacker, defender) {
+ return await Item.create({
+ name: "Empoignade en cours de " + attacker.name + ' sur ' + defender.name, type: 'empoignade',
+ img: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp",
+ system: { description: "", empoignadeid: randomID(16), compteempoigne: 0, empoigneurid: attacker.id, empoigneid: defender.id, ptsemp: 0, empoigneurname: attacker.name, empoignename: defender.name }
+ },
+ {
+ temporary: true
+ })
+ }
+}
\ No newline at end of file
diff --git a/module/rdd-main.js b/module/rdd-main.js
index d8dde122..a45f2a9f 100644
--- a/module/rdd-main.js
+++ b/module/rdd-main.js
@@ -174,7 +174,7 @@ export class SystemReveDeDragon {
"recettealchimique", "musique", "chant", "danse", "jeu", "recettecuisine", "oeuvre",
"meditation", "queue", "ombre", "souffle", "tete", "casetmr", "sort", "sortreserve",
"nombreastral", "tache", "maladie", "poison", "possession",
- "tarot", "extraitpoetique"
+ "tarot", "extraitpoetique", "empoignade"
], makeDefault: true
});
CONFIG.Combat.documentClass = RdDCombatManager;
diff --git a/module/rdd-utility.js b/module/rdd-utility.js
index 6b2bc787..50e47113 100644
--- a/module/rdd-utility.js
+++ b/module/rdd-utility.js
@@ -15,6 +15,7 @@ import { RdDItemCompetence } from "./item-competence.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { RdDRaretes } from "./item/raretes.js";
+import { RdDEmpoignade } from "./rdd-empoignade.js";
/* -------------------------------------------- */
// This table starts at 0 -> niveau -10
@@ -688,6 +689,44 @@ export class RdDUtility {
RdDPossession.onDefensePossession(attackerId, defenderId, possessionId)
});
+ html.on("click", '.defense-empoignade-cac', event => {
+ const chatMessage = ChatUtility.getChatMessage(event);
+ const rollData = ChatUtility.getMessageData(chatMessage, 'empoignade-roll-data');
+ let defenseMode = event.currentTarget.attributes['data-defense-mode'].value
+ RdDEmpoignade.onDefenseEmpoignade(rollData, defenseMode, "Corps à corps", "melee")
+ });
+ html.on("click", '.defense-empoignade-esquive', event => {
+ const chatMessage = ChatUtility.getChatMessage(event);
+ const rollData = ChatUtility.getMessageData(chatMessage, 'empoignade-roll-data');
+ let defenseMode = event.currentTarget.attributes['data-defense-mode'].value
+ RdDEmpoignade.onDefenseEmpoignade(rollData, defenseMode, "Esquive", "derobee")
+ });
+ html.on("click", '.empoignade-poursuivre', event => {
+ let attackerId = event.currentTarget.attributes['data-attackerId'].value
+ let defenderId = event.currentTarget.attributes['data-defenderId'].value
+ RdDEmpoignade.onAttaqueEmpoignadeValidee(game.actors.get(attackerId), game.actors.get(defenderId))
+ });
+ html.on("click", '.empoignade-entrainer-sol', event => {
+ const chatMessage = ChatUtility.getChatMessage(event);
+ const rollData = ChatUtility.getMessageData(chatMessage, 'empoignade-roll-data');
+ RdDEmpoignade.entrainerAuSol(rollData)
+ ChatUtility.removeChatMessageId(chatMessage.id)
+ });
+ html.on("click", '.empoignade-projeter-sol', event => {
+ const chatMessage = ChatUtility.getChatMessage(event);
+ const rollData = ChatUtility.getMessageData(chatMessage, 'empoignade-roll-data');
+ RdDEmpoignade.projeterAuSol(rollData)
+ ChatUtility.removeChatMessageId(chatMessage.id)
+ });
+ html.on("change", '.empoignade-perte-endurance', event => {
+ const chatMessage = ChatUtility.getChatMessage(event);
+ const rollData = ChatUtility.getMessageData(chatMessage, 'empoignade-roll-data');
+ if (event.currentTarget.value && event.currentTarget.value != "none") {
+ RdDEmpoignade.perteEndurance(rollData, event.currentTarget.value)
+ ChatUtility.removeChatMessageId(chatMessage.id)
+ }
+ });
+
// gestion bouton tchat Acheter
html.on("click", '.button-acheter', event => {
const venteData = DialogItemAchat.preparerAchat(event.currentTarget);
diff --git a/module/rolldata-ajustements.js b/module/rolldata-ajustements.js
index dd5d19e4..b42884f4 100644
--- a/module/rolldata-ajustements.js
+++ b/module/rolldata-ajustements.js
@@ -139,6 +139,12 @@ export const referenceAjustements = {
isUsed: (rollData, actor) => rollData.ethylisme != undefined,
getLabel: (rollData, actor) => "Ethylisme - " + RdDUtility.getNomEthylisme(rollData.ethylisme),
getValue: (rollData, actor) => rollData.ethylisme,
+ },
+ tailleempoignade: {
+ isVisible: (rollData, actor) => rollData.isEmpoignade,
+ isUsed: (rollData, actor) => rollData.isEmpoignade,
+ getLabel: (rollData, actor) => "Malus de taille",
+ getValue: (rollData, actor) => rollData.malusTaille,
}
}
diff --git a/system.json b/system.json
index ad8e69dc..a75597c7 100644
--- a/system.json
+++ b/system.json
@@ -1,8 +1,8 @@
{
"id": "foundryvtt-reve-de-dragon",
"title": "Rêve de Dragon",
- "version": "10.7.7",
- "download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-10.7.7.zip",
+ "version": "10.7.9",
+ "download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-10.7.8.zip",
"manifest": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/v10/system.json",
"compatibility": {
"minimum": "10",
diff --git a/template.json b/template.json
index 149ba47f..785059c7 100644
--- a/template.json
+++ b/template.json
@@ -538,7 +538,7 @@
"service",
"meditation", "rencontre", "queue", "ombre", "souffle", "tete", "casetmr", "signedraconique", "sort", "sortreserve",
"nombreastral", "tache", "blessure", "maladie", "poison", "possession",
- "tarot", "extraitpoetique"
+ "tarot", "extraitpoetique", "empoignade"
],
"templates": {
"description": {
@@ -596,6 +596,16 @@
"ispossession": false,
"dommages": 0
},
+ "empoignade": {
+ "templates": ["description"],
+ "empoignadeid": "",
+ "empoigneurid": "",
+ "empoigneid": "",
+ "pointsemp": 0,
+ "empoigneurname": "",
+ "empoignename": "",
+ "ausol": false
+ },
"possession": {
"templates": ["description"],
"typepossession": "",
diff --git a/templates/actor/combat.html b/templates/actor/combat.html
index b7fed5fd..b8edb5ab 100644
--- a/templates/actor/combat.html
+++ b/templates/actor/combat.html
@@ -40,4 +40,29 @@
{{/each}}
+
+
+
\ No newline at end of file
diff --git a/templates/chat-empoignade-actions.html b/templates/chat-empoignade-actions.html
new file mode 100644
index 00000000..85688188
--- /dev/null
+++ b/templates/chat-empoignade-actions.html
@@ -0,0 +1,39 @@
+
+
+ {{attackerName}} a empoigné {{defenderName}}
+
+
+
diff --git a/templates/chat-empoignade-entrainer-sol.html b/templates/chat-empoignade-entrainer-sol.html
new file mode 100644
index 00000000..2185877a
--- /dev/null
+++ b/templates/chat-empoignade-entrainer-sol.html
@@ -0,0 +1,7 @@
+
+
+ {{attackerName}} a entraîné {{defenderName}} au sol. L'empoignade peut continuer.
+
+
+
+
diff --git a/templates/chat-empoignade-perte-endurance.html b/templates/chat-empoignade-perte-endurance.html
new file mode 100644
index 00000000..c83803e7
--- /dev/null
+++ b/templates/chat-empoignade-perte-endurance.html
@@ -0,0 +1,7 @@
+
+
+ {{attackerName}} a fait perdre de l'endurance à {{defenderName}}, qui reste immobilisé. L'empoignade peut continuer.
+
+
+
+
diff --git a/templates/chat-empoignade-projeter-sol.html b/templates/chat-empoignade-projeter-sol.html
new file mode 100644
index 00000000..7d937191
--- /dev/null
+++ b/templates/chat-empoignade-projeter-sol.html
@@ -0,0 +1,7 @@
+
+
+ {{attackerName}} a projeté {{defenderName}} au sol. L'empoignade est terminée et a été supprimée.
+
+
+
+
diff --git a/templates/chat-empoignade-resultat.html b/templates/chat-empoignade-resultat.html
new file mode 100644
index 00000000..cacb36c4
--- /dev/null
+++ b/templates/chat-empoignade-resultat.html
@@ -0,0 +1,85 @@
+
+
+ {{#if (eq mode "empoigner")}}
+ {{attackerName}} tente d'empoigner {{defenderName}}
+ {{/if}}
+ {{#if (eq mode "contrer-empoigner")}}
+ {{defenderName}} tente de contrer l'empoignade de {{attackerName}}
+ {{/if}}
+ {{#if (eq mode "liberer")}}
+ {{attackerName}} tente de se libérer de l'empoignade de {{defenderName}}
+ {{/if}}
+ {{#if (eq mode "contrer-liberer")}}
+ {{defenderName}} tente de contrer la libération de {{attackerName}}
+ {{/if}}
+
+{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.html"}}
+
+
+
+
+ {{#if (gte empoignade.system.pointsemp 2)}}
+
+
{{defenderName}} est empoigné et immobilisé par {{attackerName}} !
+
+ {{else}}
+
+
+
+ {{#if (eq mode "empoigner")}}
+ {{#if empoignade.isSuccess}}
+
+ Contrer l'empoignade (Corps à Corps)
+
+ {{#if (eq empoignade.system.pointsemp 0)}}
+
+ Contrer l'empoignade (Esquive)
+
+ {{/if}}
+ {{else}}
+ La Tentative d'empoignade a échoué !
+ {{/if}}
+ {{/if}}
+
+ {{#if (eq mode "liberer")}}
+ {{#if empoignade.isSuccess}}
+
+ Contrer la libération (Corps à Corps)
+
+ {{else}}
+ La Tentative de libération a échouée !
+ {{/if}}
+ {{/if}}
+
+ {{#if (eq mode "contrer-empoigner")}}
+ {{#if rolled.isSuccess}}
+ La tentative de contrer l'empoignade est un succès!
+ {{else}}
+ La tentative de contrer l'empoignade est un échec!
+ {{/if}}
+ {{/if}}
+
+ {{#if (eq mode "contrer-liberer")}}
+ {{#if rolled.isSuccess}}
+ La tentative de contrer la libération est un succès!
+ {{else}}
+ La tentative de contrer la libération est un échec!
+ {{/if}}
+ {{/if}}
+
+
Points d'Emp: {{empoignade.system.pointsemp}}
+
+ {{/if}}
+
diff --git a/templates/chat-empoignade-valider.html b/templates/chat-empoignade-valider.html
new file mode 100644
index 00000000..b597f976
--- /dev/null
+++ b/templates/chat-empoignade-valider.html
@@ -0,0 +1,20 @@
+
+
+ {{attackerName}} tente d'empoigner {{defenderName}}
+
+
+
+
+
+
+ {{attacker.name}} tente d'empoigner {{defender.name}}, qui est équipé d'une arme de mêlée. {{defender.name}}
+ a automatiquement l'initiative sur {{attacker.name}}, et bénéficie d'un bonus de +4 à son attaque. Assurez vous
+ d'avoir effectué cette attaque avant de poursuivre l'empoignade. Ce cas s'applique également si {{defender.name}}
+ combat à mains nues.
+
+
+ Poursuivre l'empoignade
+
+
+
\ No newline at end of file
diff --git a/templates/dialog-roll-defense-empoignade.html b/templates/dialog-roll-defense-empoignade.html
new file mode 100644
index 00000000..f810a9ea
--- /dev/null
+++ b/templates/dialog-roll-defense-empoignade.html
@@ -0,0 +1,22 @@
+
diff --git a/templates/item-empoignade-sheet.html b/templates/item-empoignade-sheet.html
new file mode 100644
index 00000000..aff87868
--- /dev/null
+++ b/templates/item-empoignade-sheet.html
@@ -0,0 +1,11 @@
+