Gestion des difficultés de Possession

- gestion de la difficulté imposée sur la défense
- gestion des particulières en attaque considérées en finesse
- utilisation du rêve actuel pour les personnages
This commit is contained in:
Vincent Vandemeulebrouck 2023-06-14 01:48:32 +02:00
parent e46f35ef92
commit 2db6895c76
8 changed files with 146 additions and 67 deletions

View File

@ -45,7 +45,7 @@ const POSSESSION_SANS_DRACONIC = {
name: 'Sans draconic',
system: {
niveau: 0,
defaut_carac: "reve",
defaut_carac: "reve-actuel",
}
};
@ -275,12 +275,12 @@ export class RdDActor extends RdDBaseActor {
.sort(Misc.descending(it => it.system.niveau))
.find(it=>true);
if (possession) {
return duplicate(possession);
return possession.clone();
}
const draconics = [...this.getDraconicList().filter(it => it.system.niveau >= 0),
const draconics = [...this.getDraconicList().filter(it => it.system.niveau >= 0).map(it =>it.clone()),
POSSESSION_SANS_DRACONIC]
.sort(Misc.descending(it => it.system.niveau));
return duplicate(draconics[0]);
return draconics[0];
}
getPossession(possessionId) {
@ -780,7 +780,7 @@ export class RdDActor extends RdDBaseActor {
async combattreReveDeDragon(force) {
let rollData = {
actor: this,
competence: duplicate(this.getDraconicOuPossession()),
competence: this.getDraconicOuPossession(),
canClose: false,
rencontre: await game.system.rdd.rencontresTMR.getReveDeDragon(force),
tmr: true,
@ -2301,14 +2301,14 @@ export class RdDActor extends RdDBaseActor {
carac: this.system.carac,
competence: this.getCompetence(idOrName)
}
if (rollData.competence.type == 'competencecreature') {
if (rollData.competence.system.iscombat && options.tryTarget && Targets.hasTargets()) {
if (rollData.competence.type == TYPES.competencecreature) {
const arme = RdDItemCompetenceCreature.armeCreature(rollData.competence)
if (arme && options.tryTarget && Targets.hasTargets()) {
Targets.selectOneToken(target => {
if (rollData.competence.system.ispossession) {
if (arme.action == "possession") {
RdDPossession.onAttaquePossession(target, this, rollData.competence)
}
else {
const arme = RdDItemCompetenceCreature.armeCreature(rollData.competence)
RdDCombat.rddCombatTarget(target, this).attaque(competence, arme)
}
});
@ -3135,9 +3135,7 @@ export class RdDActor extends RdDBaseActor {
/* -------------------------------------------- */
conjurerPossession(possession) {
// TODO: choix de la compétence de draconic ou de possession
let draconic = this.getDraconicOuPossession();
RdDPossession.onConjurerPossession(this, draconic, possession)
RdDPossession.onConjurerPossession(this, possession)
}
/* -------------------------------------------- */

View File

@ -495,6 +495,25 @@ class _10_7_19_CategorieCompetenceCreature extends Migration {
}
}
class _10_7_19_PossessionsEntiteVictime extends Migration {
get code() { return "possessions-entite-victime"; }
get version() { return "10.7.19"; }
async migrate() {
await this.applyItemsUpdates(items => items
.filter(it => TYPES.possession == it.type)
.map(it => this.migratePossession(it))
);
}
migratePossession(it) {
return { _id: it.id,
'system.entite.actorid': it.system.possesseurid,
'system.victime.actorid': it.system.possedeid
}
}
}
export class Migrations {
static getMigrations() {
return [
@ -512,6 +531,7 @@ export class Migrations {
new _10_5_0_UpdatePeriodicite(),
new _10_7_0_MigrationBlessures(),
new _10_7_19_CategorieCompetenceCreature(),
new _10_7_19_PossessionsEntiteVictime(),
];
}

View File

@ -1,4 +1,5 @@
import { RdDCarac } from "./rdd-carac.js";
import { RdDPossession } from "./rdd-possession.js";
const conditionsTactiques = [
{ type: '', descr: '', dmg: 0, attaque: 0, parade: 0, esquive: true },
@ -27,6 +28,9 @@ export class RdDBonus {
if (rollData.isEmpoignade && rollData.rolled?.isPart) {
return true
}
if (RdDPossession.isDefensePossession(rollData)) {
return RdDPossession.isPossessionFinesse(rollData)
}
return rollData.attackerRoll?.particuliere == 'finesse';
}
@ -74,7 +78,7 @@ export class RdDBonus {
/* -------------------------------------------- */
static _dmgArme(rollData) {
if ( rollData.arme) {
if (rollData.arme) {
let dmgBase = rollData.arme.system.dommagesReels ?? Number(rollData.arme.system.dommages ?? 0);
//Le bonus dégats magiques ne peut pas faire dépasser le bonus de l'arme (cf p.278)
return dmgBase + Math.min(dmgBase, rollData.arme.system.magique ? rollData.arme.system.ecaille_efficacite : 0);

View File

@ -1,9 +1,9 @@
/* -------------------------------------------- */
import { RdDCombat } from "./rdd-combat.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDRoll } from "./rdd-roll.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { Targets } from "./targets.js";
import { TYPES } from "./item.js";
/* -------------------------------------------- */
/* On part du principe qu'une entité démarre tjs
@ -20,9 +20,9 @@ export class RdDPossession {
/* -------------------------------------------- */
static searchPossessionFromEntite(attacker, defender) {
let poss = attacker.items.find(poss => poss.type == 'possession' && poss.system.possedeid == defender.id);
let poss = attacker.items.find(poss => poss.type == TYPES.possession && poss.system.victime.actorid == defender.id);
if (!poss) {
poss = defender.items.find(poss => poss.type == 'possession' && poss.system.possedeid == defender.id);
poss = defender.items.find(poss => poss.type == TYPES.possession && poss.system.victime.actorid == defender.id);
}
return poss && duplicate(poss) || undefined;
}
@ -31,13 +31,13 @@ export class RdDPossession {
static async onAttaquePossession(target, attacker, competence, suitePossession = undefined) {
const defender = target.actor;
const fromEntite = RdDPossession.searchPossessionFromEntite(attacker, defender);
const isNouvelle = !suitePossession && ! fromEntite;
const isNouvelle = !suitePossession && !fromEntite;
const possession = (suitePossession ?? fromEntite ?? (await RdDPossession.createPossession(attacker, defender)));
RdDPossession.$updateEtatPossession(possession)
let rollData = {
mode: "possession",
mode: "attaque",
isECNIDefender: false,
competence: competence.clone(),
possession: possession,
@ -45,25 +45,26 @@ export class RdDPossession {
defender: defender,
targetToken: Targets.extractTokenData(target)
};
if (attacker.isCreatureEntite()) {
RdDItemCompetenceCreature.setRollDataCreature(rollData)
}
RdDPossession.selectCompetenceDraconicOuPossession(rollData, attacker)
await RdDPossession.$rollAttaquePossession(attacker, rollData, isNouvelle);
}
/* -------------------------------------------- */
static async onConjurerPossession(attacker, competence, possession) {
static async onConjurerPossession(attacker, possession) {
possession = duplicate(possession);
RdDPossession.$updateEtatPossession(possession)
const defender = game.actors.get(possession.system.entite.actorid);
let rollData = {
mode: "possession",
mode: "attaque",
isECNIDefender: true,
competence: competence,
possession: possession,
attacker: attacker,
defender: game.actors.get(possession.system.possesseurid)
defender: defender,
};
RdDPossession.selectCompetenceDraconicOuPossession(rollData, attacker)
await RdDPossession.$rollAttaquePossession(attacker, rollData);
}
@ -71,7 +72,7 @@ export class RdDPossession {
static async onDefensePossession(attackerId, defenderId, possessionId) {
let attacker = game.actors.get(attackerId)
let possession = attacker?.getPossession(possessionId)
defenderId = defenderId ?? possession?.system.possesseurid ?? undefined
defenderId = defenderId ?? possession?.system.entite.actorid ?? undefined
let defender = game.actors.get(defenderId)
possession = possession ?? defender?.getPossession(possessionId) ?? undefined;
@ -82,19 +83,29 @@ export class RdDPossession {
possession = duplicate(possession)
// Update for draconic roll
let rollData = {
mode: "conjuration",
mode: "defense",
isECNIDefender: defender.type == "entite",
possession: possession,
attacker: attacker,
defender: defender,
competence: defender.getDraconicOuPossession(),
selectedCarac: defender.system.carac.reve,
forceCarac: { 'reve-actuel': { label: "Rêve Actuel", value: defender.getReveActuel() } }
}
rollData.competence.system.defaut_carac = 'reve-actuel'
RdDPossession.selectCompetenceDraconicOuPossession(rollData, defender)
rollData.diffLibre = RdDPossession.getInfoAttaque(rollData).diffLibre
await RdDPossession.$rollDefensePossession(defender, rollData);
}
static selectCompetenceDraconicOuPossession(rollData, rollingActor) {
rollData.competence = rollingActor.getDraconicOuPossession();
if (rollingActor.isCreatureEntite()) {
RdDItemCompetenceCreature.setRollDataCreature(rollData)
}
else {
rollData.selectedCarac = rollingActor.system.carac.reve
rollData.forceCarac = { 'reve-actuel': { label: "Rêve Actuel", value: rollingActor.getReveActuel() } }
rollData.competence.system.defaut_carac = 'reve-actuel'
}
}
/* -------------------------------------------- */
static async $rollAttaquePossession(attacker, rollData, isNouvelle = false) {
@ -104,21 +115,22 @@ export class RdDPossession {
name: 'jet-possession',
label: rollData.isECNIDefender ? 'Conjurer la possession' : 'Possession',
callbacks: [
{ condition: r => (r.rolled.isSuccess), action: async (r) => await RdDPossession.$onRollPossession(r, true, isNouvelle) },
{ condition: r => (r.rolled.isEchec), action: async (r) => await RdDPossession.$onRollPossession(r, false, isNouvelle) },
{ action: async (r) => await RdDPossession.$onRollPossession(r, isNouvelle) },
]
});
dialog.render(true);
dialog.render(true);
}
/* -------------------------------------------- */
static async $onRollPossession(rollData, isSuccess, isNouvelle = false) {
rollData.possession.isSuccess = isSuccess;
RdDPossession.$updateEtatPossession(rollData.possession);
static async $onRollPossession(rollData, isNouvelle = false) {
rollData.possession.isSuccess = rollData.rolled.isSuccess;
RdDPossession.$updateEtatPossession(rollData.possession, rollData);
if (isNouvelle) {
// Creer la possession sur le defenseur
rollData.defender.createEmbeddedDocuments('Item', [rollData.possession.toObject()])
await rollData.defender.createEmbeddedDocuments('Item', [rollData.possession.toObject()])
}
const possession = (rollData.isECNIDefender ? rollData.attacker : rollData.defender).getPossession(rollData.possession.system.possessionid)
RdDPossession.storePossessionAttaque(possession, rollData)
await RdDResolutionTable.displayRollData(rollData, rollData.attacker, 'chat-resultat-possession.html');
}
@ -131,31 +143,38 @@ export class RdDPossession {
label: 'Conjurer une Possession',
callbacks: [
{ action: async (r) => await RdDPossession.$onRollConjuration(r) }
]
}
);
]
}
);
dialog.render(true);
}
}
/* -------------------------------------------- */
static async $onRollConjuration(rollData) {
let actor = game.actors.get(rollData.possession.system.possedeid)
let victime = game.actors.get(rollData.possession.system.victime.actorid)
let compteur = rollData.possession.system.compteur
if (!rollData.rolled.isSuccess) {
if (rollData.isECNIDefender) {
rollData.possession.system.compteur--
compteur--
} else {
rollData.possession.system.compteur++
compteur++
}
let update = { _id: rollData.possession._id, "system.compteur": rollData.possession.system.compteur }
await actor.updateEmbeddedDocuments('Item', [update])
}
const possession = victime.getPossession(rollData.possession.system.possessionid)
await possession.update({
system: {
compteur: compteur,
entite: { diffLibre: 0, finesse: false },
victime: { diffLibre: 0, finesse: false }
}
})
rollData.possession = possession
RdDPossession.$updateEtatPossession(rollData.possession)
await RdDResolutionTable.displayRollData(rollData,rollData.defender, 'chat-resultat-possession.html')
await RdDResolutionTable.displayRollData(rollData, rollData.defender, 'chat-resultat-possession.html')
if (rollData.possession.isPosseder || rollData.possession.isConjurer) {
// conjuration
actor.deleteEmbeddedDocuments("Item", [rollData.possession._id])
victime.deleteEmbeddedDocuments("Item", [rollData.possession._id])
}
}
@ -180,13 +199,43 @@ export class RdDPossession {
}
}
/* -------------------------------------------- */
static isPossessionFinesse(rollData) {
return RdDPossession.getInfoAttaque(rollData).finesse
}
/* -------------------------------------------- */
static getInfoAttaque(rollData) {
return rollData.possession.system[rollData.isECNIDefender ? 'victime' : 'entite'];
}
/* -------------------------------------------- */
static isDefensePossession(rollData) {
return rollData.possession && rollData.mode == "defense"
}
/* -------------------------------------------- */
static storePossessionAttaque(possession, rollData = undefined) {
const attaquant = rollData?.isECNIDefender ? 'victime' : 'entite'
possession.update({
[`system.${attaquant}`]: {
diffLibre: rollData?.diffLibre ?? 0,
finesse: rollData?.rolled.isPart ?? false
}
})
}
/* -------------------------------------------- */
static async createPossession(attacker, defender) {
return await Item.create({
name: "Possession en cours de " + attacker.name, type: 'possession',
img: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp",
system: { description: "", typepossession: attacker.name, possede: false, possessionid: randomID(16), possesseurid: attacker.id, possedeid: defender.id, date: 0, compteur: 0 }
},
name: "Possession en cours de " + attacker.name, type: 'possession',
img: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp",
system: {
description: "", typepossession: attacker.name,
possede: false,
possessionid: randomID(16),
entite: { actorid: attacker.id },
victime: { actorid: defender.id },
compteur: 0
}
},
{
temporary: true
})

View File

@ -75,8 +75,8 @@ export class RdDTokenHud {
(event) => {
const actionIndex = event.currentTarget.attributes['data-action-index']?.value;
const action = hudData.actions[actionIndex];
if (action.action == 'possession') {
const possession = combatant.actor.getPossession(action.system.possessionid);
const possession = action.action == 'possession' ? combatant.actor.getPossession(action.system.possessionid) : undefined;
if (possession) {
combatant.actor.conjurerPossession(possession);
}
else {

View File

@ -5,6 +5,7 @@ import { RdDItemSort } from "./item-sort.js";
import { Misc } from "./misc.js";
import { RdDBonus } from "./rdd-bonus.js";
import { RdDCarac } from "./rdd-carac.js";
import { RdDPossession } from "./rdd-possession.js";
import { RdDUtility } from "./rdd-utility.js";
import { ReglesOptionelles } from "./settings/regles-optionelles.js";
@ -30,7 +31,7 @@ export const referenceAjustements = {
},
diffLibre: {
isUsed: (rollData, actor) => rollData.diffLibre != undefined,
getLabel: (rollData, actor) => rollData.selectedSort?.name ?? rollData.attackerRoll ? 'Imposée' : 'Libre',
getLabel: (rollData, actor) => rollData.selectedSort?.name ?? rollData.attackerRoll ?? RdDPossession.isDefensePossession(rollData) ? 'Imposée' : 'Libre',
getValue: (rollData, actor) => rollData.selectedSort
? RdDItemSort.getDifficulte(rollData.selectedSort, rollData.diffLibre)
: rollData.diffLibre ?? rollData.competence?.system.default_diffLibre ?? 0

View File

@ -611,10 +611,17 @@
"typepossession": "",
"possede": false,
"possessionid": "",
"possesseurid": "",
"possedeid": "",
"compteur": 0,
"date": 0
"entite": {
"actorid": "",
"diffLibre": 0,
"finesse": false
},
"victime": {
"actorid": "",
"diffLibre": 0,
"finesse": false
},
"compteur": 0
},
"blessure": {
"templates": ["temporel"],

View File

@ -1,6 +1,6 @@
<img class="chat-icon" src="{{competence.img}}" />
<h4>
{{#if (eq mode "possession")}}
{{#if (eq mode "attaque")}}
{{attacker.name}} tente de {{#if isECNIDefender}}conjurer la possession de{{else}}posséder{{/if}} {{defender.name}}
{{else}}
{{defender.name}} tente de {{#if isECNIDefender}}résister à{{else}}conjurer la possession de{{/if}} {{attacker.name}}
@ -12,7 +12,7 @@
<div>
<span class='chat-card-button-area'>
<br>
{{#if (eq mode "possession")}}
{{#if (eq mode "attaque")}}
{{#if possession.isSuccess}}
<a class='defense-possession chat-card-button'
data-attackerId='{{attacker.id}}'