/* -------------------------------------------- */ 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 }) } }