262 lines
9.7 KiB
JavaScript
262 lines
9.7 KiB
JavaScript
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 }])
|
|
}
|
|
}
|
|
}
|
|
}
|