import { ITEM_TYPES, RDD_CONFIG } from "./constants.js"; import { RollBasicParts } from "./roll/roll-basic-parts.mjs"; import { ChatUtility } from "./chat-utility.js"; import RollDialog from "./roll/roll-dialog.mjs"; import { Targets } from "./targets.js"; import { RdDUtility } from "./rdd-utility.js"; import { ROLL_TYPE_POSSESSION } from "./roll/roll-constants.mjs"; import { TokenActor } from "./technical/actor-token.mjs"; export const ACTIONS_POSSESSION = { ATTAQUE: 'attaque', POSSEDER: 'posseder', CONJURER: 'conjurer', DEFENSE: 'defense', DEFENSE_POSSESSION: 'defense-possession', DEFENSE_CONJURATION: 'defense-conjuration' } export class RdDPossessionV2 { static init() { } static $isInverse(entite, victime) { return !entite.actor.isEntiteNonIncarnee() && victime.actor.isEntiteNonIncarnee() } /* -------------------------------------------- */ static findPossession(entite, victime) { if (RdDPossessionV2.$isInverse(entite, victime)) { return RdDPossessionV2.findPossession(victime, entite) } return victime.actor.itemTypes[ITEM_TYPES.possession].find(it => it.system.entiteid == entite.id) } static async createPossessionIfMissing(entite, victime) { if (RdDPossessionV2.$isInverse(entite, victime)) { return await RdDPossessionV2.createPossessionIfMissing(victime, entite) } const existing = RdDPossessionV2.findPossession(entite, victime) if (!existing) { await victime.actor.createEmbeddedDocuments('Item', [{ name: `Possession de ${entite.name}`, type: ITEM_TYPES.possession, img: RDD_CONFIG.icons.possession, system: { entiteid: entite.actor.id, entitetokenid: entite.token.id, victimeid: victime.actor.id, victimetokenid: victime.token.id, compteur: 0 } }]) } } static getTypePossession(active, opponent) { const itemPossession = RdDPossessionV2.findPossession(active, opponent) const isEntite = active.actor.isEntiteNonIncarnee() && !opponent.actor.isEntiteNonIncarnee() const compteur = itemPossession?.system.compteur ?? 0 return { isEntite: isEntite, isPersonnage: active.actor.isPersonnage(), isCompteurPossession: Math.sign(compteur) >= 0, compteur: Math.abs(compteur) } } static getTypePossessionAction(active, opponent, action) { const possession = RdDPossessionV2.getTypePossession(active, opponent) possession.isAttaque = RdDPossessionV2.isAttaque(action) possession.action = RdDPossessionV2.$getAction(possession.isAttaque, possession.isEntite) return possession } static $getAction(isAttaque, isEntite) { if (isAttaque) { return isEntite ? ACTIONS_POSSESSION.POSSEDER : ACTIONS_POSSESSION.CONJURER } return isEntite ? ACTIONS_POSSESSION.DEFENSE_CONJURATION : ACTIONS_POSSESSION.DEFENSE_POSSESSION } static actionTitle(action) { switch (action) { case ACTIONS_POSSESSION.POSSEDER: return "tente de posséder" case ACTIONS_POSSESSION.CONJURER: return "tente de conjurer" case ACTIONS_POSSESSION.DEFENSE_POSSESSION: return "résiste à la possession de" case ACTIONS_POSSESSION.DEFENSE_CONJURATION: return "résiste à la conjuration de" case ACTIONS_POSSESSION.DEFENSE: return "résiste à " } return "lutte contre" } static isDefense(action) { return [ACTIONS_POSSESSION.DEFENSE, ACTIONS_POSSESSION.DEFENSE_POSSESSION, ACTIONS_POSSESSION.DEFENSE_CONJURATION].includes(action) } static isAttaque(action) { return [ACTIONS_POSSESSION.ATTAQUE, ACTIONS_POSSESSION.POSSEDER, ACTIONS_POSSESSION.CONJURER].includes(action) } static async rollAttaquePossession(actor) { const selectedToken = RdDUtility.getSelectedToken(actor) Targets.selectOneTargetToken(async target => { RollDialog.create( { ids: { actorId: actor.id, actorTokenId: selectedToken.id, opponentId: target.actor.id, opponentTokenId: target.id }, passeArme: foundry.utils.randomID(16), type: { allowed: [ROLL_TYPE_POSSESSION], current: ROLL_TYPE_POSSESSION, possession: { action: ACTIONS_POSSESSION.ATTAQUE } }, }, { onRollDone: RollDialog.onRollDoneClose, callbacks: [ async (roll) => await RdDPossessionV2.createPossessionIfMissing(roll.active, roll.opponent), async (roll) => RdDPossessionV2.$setParticuliereFinesse(roll), async (roll) => await RdDPossessionV2.chatMessageDefensePossession(roll) ] }) }) } static async rollConjurerPossession(actor, possession) { if (possession.system.possede){ ui.notifications.warn(`${actor.name} est totalement possédé, impossible de conjurer l'entité`) return } RollDialog.create( { ids: { actorId: possession.system.victimeid, actorTokenId: possession.system.victimetokenid, opponentId: possession.system.entiteid, opponentTokenId: possession.system.entitetokenid }, passeArme: foundry.utils.randomID(16), type: { allowed: [ROLL_TYPE_POSSESSION], current: ROLL_TYPE_POSSESSION, possession: { action: ACTIONS_POSSESSION.ATTAQUE } }, }, { onRollDone: RollDialog.onRollDoneClose, callbacks: [ async (roll) => await RdDPossessionV2.createPossessionIfMissing(roll.active, roll.opponent), async (roll) => RdDPossessionV2.$setParticuliereFinesse(roll), async (roll) => await RdDPossessionV2.chatMessageDefensePossession(roll) ] }) } static $setParticuliereFinesse(roll) { if (roll.rolled.isPart) { roll.particuliere = RDD_CONFIG.particuliere.finesse.key } } static async rollDefensePossession(savedRoll, chatMessage) { RollBasicParts.restore(savedRoll) const attackerRoll = savedRoll.attackerRoll RollDialog.create( { ids: savedRoll.ids, passeArme: attackerRoll.passeArme, type: { allowed: [ROLL_TYPE_POSSESSION], current: ROLL_TYPE_POSSESSION, possession: { action: ACTIONS_POSSESSION.DEFENSE } }, selected: { diff: { value: attackerRoll.selected?.diff?.value ?? 0 } }, attackerRoll: attackerRoll }, { onRollDone: RollDialog.onRollDoneClose, callbacks: [ async roll => await RdDPossessionV2.onRollDefense(roll), ChatUtility.remover(chatMessage) ] }); } static async onRollDefense(defense) { if (defense.rolled.isEchec) { await RdDPossessionV2.addPointPossession(defense.opponent, defense.active) } RdDPossessionV2.resetPossession(defense) } static async onMarquerPointPossession(roll) { roll.type = {} await RdDPossessionV2.addPointPossession(roll.opponent, roll.active) RdDPossessionV2.resetPossession(roll) await ChatMessage.create({ // message privé: du défenseur à lui même (et aux GMs) speaker: ChatMessage.getSpeaker({ actor: roll.active.actor, token: roll.active.token }), alias: roll.opponent.name, whisper: ChatUtility.getOwners(roll.active.actor), content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/possession/chat-message-marquer.hbs`, roll) }) } static resetPossession(roll) { roll.type.possession = foundry.utils.mergeObject( roll.type.possession ?? {}, RdDPossessionV2.getTypePossession(roll.opponent, roll.active)) } static async addPointPossession(entite, victime, points = 1) { if (RdDPossessionV2.$isInverse(entite, victime)) { return await RdDPossessionV2.addPointPossession(victime, entite, - points) } const existing = RdDPossessionV2.findPossession(entite, victime) if (existing) { const compteur = (existing.system.compteur ?? 0) + points await victime.actor.updateEmbeddedDocuments('Item', [{ _id: existing.id, 'system.compteur': compteur }]) } } static async chatMessageDefensePossession(attackerRoll) { const defense = RollBasicParts.prepareDefense(attackerRoll) defense.type = { possession: RdDPossessionV2.getTypePossessionAction(defense.active, defense.opponent, ACTIONS_POSSESSION.DEFENSE) } const chatDemandeDefense = await ChatMessage.create({ // message privé: du défenseur à lui même (et aux GMs) speaker: ChatMessage.getSpeaker({ actor: defense.active.actor, token: defense.active.token }), alias: attackerRoll.active.name, whisper: ChatUtility.getOwners(defense.active.actor), content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/possession/chat-demande-defense.hbs', defense) }); ChatUtility.setMessageData(chatDemandeDefense, 'demande-defense', true) // // flag pour garder les jets d'attaque/defense ChatUtility.setMessageData(chatDemandeDefense, 'rollData', { ids: defense.ids, attackerRoll: RollDialog.saveParts(attackerRoll), passeArme: defense.passeArme }) } static async onPossession(actor, possession) { if (Math.abs(possession.system.compteur) >= 2) { await ChatMessage.create({ alias: actor.getAlias(), whisper: ChatUtility.getOwners(actor), content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/possession/chat-fin-possession.hbs', { possession, active: TokenActor.fromActor(actor), opponent: TokenActor.fromActor(game.actors.get(possession.system.entiteid)) }) }) if (possession.system.compteur <= -2) { await actor.deleteEmbeddedDocuments('Item', [possession.id]) } if (possession.system.compteur >= 2) { await actor.updateEmbeddedDocuments('Item', [{ _id: possession.id, 'system.possede': true }]) } } } }