Vincent Vandemeulebrouck
bb624e8e96
Seul le propriétaire du défenseur peut effecuer les contres d'empoignade ou tenter de se libérer. Seul le propriétaire de l'empoigneur peut tenter d'empêcher la libération du défenseur, de projeter au sol, ou de faire perdre de l'endurance.
414 lines
17 KiB
JavaScript
414 lines
17 KiB
JavaScript
/* -------------------------------------------- */
|
|
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 } from "./settings/status-effects.js";
|
|
import { ReglesOptionelles } from "./settings/regles-optionelles.js";
|
|
import { TYPES } from "./item.js";
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
/* -------------------------------------------- */
|
|
export class RdDEmpoignade {
|
|
|
|
/* -------------------------------------------- */
|
|
static init() {
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static registerChatCallbacks(html) {
|
|
html.on("click", '.defense-empoignade-cac', event => {
|
|
const chatMessage = ChatUtility.getChatMessage(event);
|
|
const rollData = RdDEmpoignade.readRollEmpoignade(chatMessage);
|
|
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 = RdDEmpoignade.readRollEmpoignade(chatMessage);
|
|
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 = RdDEmpoignade.readRollEmpoignade(chatMessage);
|
|
RdDEmpoignade.entrainerAuSol(rollData)
|
|
ChatUtility.removeChatMessageId(chatMessage.id)
|
|
});
|
|
html.on("click", '.empoignade-projeter-sol', event => {
|
|
const chatMessage = ChatUtility.getChatMessage(event);
|
|
const rollData = RdDEmpoignade.readRollEmpoignade(chatMessage);
|
|
RdDEmpoignade.projeterAuSol(rollData)
|
|
ChatUtility.removeChatMessageId(chatMessage.id)
|
|
});
|
|
html.on("change", '.empoignade-perte-endurance', event => {
|
|
const chatMessage = ChatUtility.getChatMessage(event);
|
|
const rollData = RdDEmpoignade.readRollEmpoignade(chatMessage);
|
|
if (event.currentTarget.value && event.currentTarget.value != "none") {
|
|
RdDEmpoignade.perteEndurance(rollData, event.currentTarget.value)
|
|
ChatUtility.removeChatMessageId(chatMessage.id)
|
|
}
|
|
});
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static checkEmpoignadeEnCours(actor) {
|
|
// TODO: autoriser la perception? la comédie/séduction?
|
|
if (RdDEmpoignade.isEmpoignadeEnCours(actor)) {
|
|
ui.notifications.warn("Une empoignade est en cours ! Normalement, vous ne pouvez rien faire d'autre que continuer l'empoignade ou la rompre.")
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static storeRollEmpoignade(msg, rollData) {
|
|
rollData.attacker = { id: rollData.attacker.id }
|
|
rollData.defender = { id: rollData.defender.id }
|
|
ChatUtility.setMessageData(msg, "empoignade-roll-data", rollData);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static readRollEmpoignade(msg) {
|
|
const rollData = ChatUtility.getMessageData(msg, 'empoignade-roll-data');
|
|
rollData.attacker = game.actors.get(rollData.attacker.id)
|
|
rollData.defender = game.actors.get(rollData.defender.id)
|
|
return rollData
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static isEmpoignadeEnCours(actor) {
|
|
return actor.itemTypes[TYPES.empoignade].find(it => it.system.pointsemp > 0)
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static getEmpoignadeById(actor, id) {
|
|
let emp = actor.itemTypes[TYPES.empoignade].find(it => it.system.empoignadeid == id)
|
|
return emp && duplicate(emp) || undefined;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static getEmpoignade(attacker, defender) {
|
|
let emp = attacker.itemTypes[TYPES.empoignade].find(it =>
|
|
(it.system.empoigneurid == attacker.id && it.system.empoigneid == defender.id) ||
|
|
(it.system.empoigneurid == defender.id && it.system.empoigneid == attacker.id)
|
|
)
|
|
if (emp) {
|
|
return duplicate(emp);
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static getMalusTaille(emp, attacker, defender) {
|
|
// Si pas empoigné, alors 0
|
|
if (emp.system.pointsemp == 0) {
|
|
return 0
|
|
}
|
|
// p135: Malus de -1 par point de taille de différence de taille au delà de 1 (donc -2 pour une différence de 3, ...)
|
|
const diffTaille = attacker.system.carac.taille.value - defender.system.carac.taille.value;
|
|
const diffTailleAbs = Math.abs(diffTaille)
|
|
const signDiff = diffTaille > 0 ? 1 : -1
|
|
|
|
if (diffTailleAbs > 2) {
|
|
return signDiff * (diffTailleAbs - 1)
|
|
}
|
|
return 0
|
|
}
|
|
|
|
static isActionAutorisee(mode, attacker, defender) {
|
|
const acting = RdDEmpoignade.isActionDefenseur(mode) ? defender : attacker;
|
|
if (acting.getUserLevel(game.user) < CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER) {
|
|
ui.notifications.warn(`Vous n'êtes pas autorisé à choisir l'action de ${acting.name}`)
|
|
return false;
|
|
}
|
|
return true
|
|
}
|
|
|
|
static isActionDefenseur(mode) {
|
|
switch (mode) {
|
|
case "liberer":
|
|
case "contrer-empoigner":
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static async onAttaqueEmpoignade(attacker, defender) {
|
|
if (!RdDEmpoignade.isActionAutorisee("empoigner", attacker, defender)) {
|
|
return
|
|
}
|
|
|
|
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 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"
|
|
|
|
if (!RdDEmpoignade.isActionAutorisee(mode, attacker, defender)) {
|
|
return
|
|
}
|
|
|
|
let rollData = {
|
|
mode, empoignade, attacker, defender,
|
|
isEmpoignade: true,
|
|
competence: attacker.getCompetence("Corps à corps").clone(),
|
|
selectedCarac: attacker.system.carac.melee,
|
|
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');
|
|
RdDEmpoignade.storeRollEmpoignade(msg, rollData);
|
|
} else {
|
|
await RdDEmpoignade.$rollAttaqueEmpoignade(attacker, rollData, isNouvelle);
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
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: [{ action: async (r) => await RdDEmpoignade.$onRollEmpoignade(r, isNouvelle) },]
|
|
});
|
|
dialog.render(true);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static async $onRollEmpoignade(rollData, isNouvelle = false) {
|
|
let attacker = game.actors.get(rollData.attacker.id)
|
|
let defender = game.actors.get(rollData.defender.id)
|
|
|
|
|
|
if (rollData.rolled.isSuccess && isNouvelle) {
|
|
const objectEmpoignade = rollData.empoignade.toObject();
|
|
// Creer l'empoignade sur attaquant/defenseur
|
|
attacker.creerObjetParMJ(objectEmpoignade);
|
|
defender.creerObjetParMJ(objectEmpoignade);
|
|
}
|
|
|
|
rollData.empoignade.isSuccess = rollData.rolled.isSuccess;
|
|
if (rollData.rolled.isPart) {
|
|
rollData.particuliere = "finesse";
|
|
}
|
|
let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-resultat.html');
|
|
RdDEmpoignade.storeRollEmpoignade(msg, rollData);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static async onDefenseEmpoignade(attackerRoll, mode, competenceName = "Corps à corps", carac = "melee") {
|
|
let attacker = game.actors.get(attackerRoll.attacker.id)
|
|
let defender = game.actors.get(attackerRoll.defender.id)
|
|
if (!RdDEmpoignade.isActionAutorisee(mode, attacker, defender)) {
|
|
return
|
|
}
|
|
|
|
let empoignade = this.getEmpoignade(attacker, defender)
|
|
|
|
if (!empoignade) {
|
|
ui.notifications.warn("Une erreur s'est produite : Aucune empoignade trouvée !!")
|
|
return
|
|
}
|
|
|
|
empoignade = duplicate(empoignade)
|
|
let defenderRoll = {
|
|
mode, attacker, defender, empoignade, attackerRoll,
|
|
diffLibre: attackerRoll.diffLibre,
|
|
attaqueParticuliere: attackerRoll.particuliere,
|
|
competence: defender.getCompetence(competenceName).clone(),
|
|
surprise: defender.getSurprise(true),
|
|
carac: defender.system.carac,
|
|
selectedCarac: defender.system.carac[carac],
|
|
malusTaille: RdDEmpoignade.getMalusTaille(empoignade, defender, attacker),
|
|
show: {}
|
|
};
|
|
await RdDEmpoignade.$rollDefenseEmpoignade(defender, defenderRoll);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
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');
|
|
RdDEmpoignade.storeRollEmpoignade(msg, 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])
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static async entrainerAuSol(rollData) {
|
|
let attacker = game.actors.get(rollData.attacker.id)
|
|
let defender = game.actors.get(rollData.defender.id)
|
|
if (!RdDEmpoignade.isActionAutorisee("attaquant", attacker, defender)) {
|
|
return
|
|
}
|
|
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');
|
|
RdDEmpoignade.storeRollEmpoignade(msg, rollData);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static async projeterAuSol(rollData) {
|
|
let attacker = game.actors.get(rollData.attacker.id)
|
|
let defender = game.actors.get(rollData.defender.id)
|
|
if (!RdDEmpoignade.isActionAutorisee("attaquant", attacker, defender)) {
|
|
return
|
|
}
|
|
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');
|
|
RdDEmpoignade.storeRollEmpoignade(msg, rollData);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static async perteEndurance(rollData, perteMode) {
|
|
let attacker = game.actors.get(rollData.attacker.id)
|
|
let defender = game.actors.get(rollData.defender.id)
|
|
if (!RdDEmpoignade.isActionAutorisee("attaquant", attacker, defender)) {
|
|
return
|
|
}
|
|
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", -endValue);
|
|
}
|
|
if (perteMode == "end1") {
|
|
await defender.santeIncDec("endurance", -(endValue - 1));
|
|
}
|
|
if (perteMode == "endmoitie") {
|
|
await defender.santeIncDec("endurance", -Math.floor(endValue / 2));
|
|
}
|
|
if (perteMode == "endquart") {
|
|
await defender.santeIncDec("endurance", -(3 * Math.floor(endValue / 4)));
|
|
}
|
|
let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-perte-endurance.html');
|
|
RdDEmpoignade.storeRollEmpoignade(msg, rollData);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static async deleteAllEmpoignades() {
|
|
for (let actor of game.actors) {
|
|
let empIds = actor.itemTypes["empoignade"].map(it => it.id)
|
|
await actor.deleteEmbeddedDocuments('Item', empIds)
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
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
|
|
})
|
|
}
|
|
} |