Vincent Vandemeulebrouck
f22c4d2ec8
En cours de round en atteignant 2 points d'empoignade, on peut uniquement entraîner au sol. En fin de round, si la victime est immobilisée, on peut projeter, ou faire perdre de l'endurance
436 lines
17 KiB
JavaScript
436 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) {
|
|
RdDEmpoignade.$reduceActorToIds(rollData);
|
|
ChatUtility.setMessageData(msg, "empoignade-roll-data", rollData);
|
|
}
|
|
|
|
static $reduceActorToIds(rollData) {
|
|
rollData.attacker = { id: rollData.attacker.id };
|
|
rollData.defender = { id: rollData.defender.id };
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static $readRollEmpoignade(msg) {
|
|
const rollData = ChatUtility.getMessageData(msg, 'empoignade-roll-data');
|
|
RdDEmpoignade.$replaceIdsWithActors(rollData);
|
|
return rollData
|
|
}
|
|
|
|
static $replaceIdsWithActors(rollData) {
|
|
rollData.attacker = game.actors.get(rollData.attacker.id);
|
|
rollData.defender = game.actors.get(rollData.defender.id);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
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) {
|
|
if (!empoignade.system.ausol) {
|
|
let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-entrainer.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 onImmobilisation(attacker, defender, empoignade) {
|
|
const rollData = {
|
|
mode: "immobilise",
|
|
empoignade, attacker, defender,
|
|
isEmpoignade: true,
|
|
competence: attacker.getCompetence("Corps à corps").clone()
|
|
}
|
|
const msg = await ChatMessage.create({
|
|
whisper: ChatUtility.getWhisperRecipientsAndGMs(attacker.name),
|
|
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-empoignade-immobilise.html`, rollData)
|
|
})
|
|
RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
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, defenderRoll) {
|
|
const dialog = await RdDRoll.create(defender, defenderRoll,
|
|
{ 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)
|
|
}
|
|
|
|
await RdDResolutionTable.displayRollData(rollData, rollData.defender, 'chat-empoignade-resultat.html')
|
|
if (empoignade.system.pointsemp >= 2) {
|
|
let msg = await RdDResolutionTable.displayRollData(rollData, rollData.attacker, 'chat-empoignade-entrainer.html');
|
|
RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
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("immobilise", 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("immobilise", 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("immobilise", 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
|
|
})
|
|
}
|
|
} |