Compare commits

...

21 Commits

Author SHA1 Message Date
9c71827baa Add Blurette 2022-07-22 22:45:41 +02:00
fc9ef06e7b Merge pull request 'Support des blurettes' (#544) from VincentVk/foundryvtt-reve-de-dragon:v1.5 into v1.5
Reviewed-on: #544
2022-07-22 22:44:49 +02:00
Vincent Vandemeulebrouck
9e63706de6 Support des blurettes
On peut définir Blurette comme type d'entité.
Pas de jet poour s'accorder aux blurettes.
2022-07-22 21:38:20 +02:00
3958b1bdc2 Add Vincent VK fixes 2022-07-22 10:46:39 +02:00
6d6843223b Merge pull request 'Petits fixes et petits conforts' (#543) from VincentVk/foundryvtt-reve-de-dragon:v1.5 into v1.5
Reviewed-on: #543
2022-07-22 10:45:44 +02:00
Vincent Vandemeulebrouck
46f5cb67f6 Créer un acteur depuis /nom 2022-07-22 01:34:15 +02:00
Vincent Vandemeulebrouck
d51243d74f Fix Bouton "prendre"
Le bouton devenait "Acheter" car le prix après la première prise était
récupéré sous forme de string (et le template fait une comparaison de
nombre)
2022-07-22 01:01:46 +02:00
Vincent Vandemeulebrouck
34cc671f12 Fix init Autre action 2022-07-22 00:36:16 +02:00
Vincent Vandemeulebrouck
16ce6a58dd Fix accorder entite de cauchemar
A priori vieille régression, pas vue depuis.

attaquant._id est devenu attaquant.id
2022-07-22 00:31:27 +02:00
89910e234d Add Vincent fixes 2022-07-17 11:05:28 +02:00
f30df47d22 Merge pull request 'v1.5' (#542) from VincentVk/foundryvtt-reve-de-dragon:v1.5 into v1.5
Reviewed-on: #542
2022-07-17 11:04:20 +02:00
Vincent Vandemeulebrouck
c3c42bdb21 Fix compétences créatures
Ne pas ajouter toutes les compétences à une nouvelle créature,
il faut presque toutes les enlever
2022-07-17 01:54:01 +02:00
Vincent Vandemeulebrouck
14eb655382 Fix Haubert d'Oniros - rituel 2022-07-17 01:53:02 +02:00
Vincent Vandemeulebrouck
52e4375972 Fix affichage description des entités 2022-07-16 23:38:03 +02:00
8aece9cad1 Fixes pour possession 2022-07-09 08:56:44 +02:00
ffd36a045e Merge pull request 'Quelques petits fixes' (#541) from VincentVk/foundryvtt-reve-de-dragon:v1.5 into v1.5
Reviewed-on: #541
2022-07-09 08:55:48 +02:00
Vincent Vandemeulebrouck
bafc52a151 Fix: recherches incorrectes
* cas rare d'un personnage avec carac reve-actuel défini, mais sans
label, qui rend impossible de trouver une autre caractéristique, ce
qui empêche tout jet de caractéristique

* '/rdd <carac> <comp>', quand plusieurs compétences peuvent
correspondre, la première devrait être choisie... mais en pratique,
échec et rien ne se passe
2022-07-08 01:22:53 +02:00
Vincent Vandemeulebrouck
940baad04c Amélioration des possession
* messages plus clairs
* initiatives
* en cas de possession en cours, c'est la seule action possible
* accès dans le HUD
2022-07-03 15:32:24 +02:00
70c26ebfe0 Fix possession 2022-07-02 08:54:55 +02:00
782c6a8fe2 Merge pull request 'Fix possession' (#540) from VincentVk/foundryvtt-reve-de-dragon:v1.5 into v1.5
Reviewed-on: #540
2022-07-02 08:53:30 +02:00
Vincent Vandemeulebrouck
b417fdfe32 Fix possession
On peut maintenant lutter pour les haut-rêvants
Les messages ont été clarifiés
2022-07-02 01:41:55 +02:00
24 changed files with 431 additions and 333 deletions

View File

@@ -94,7 +94,7 @@ export class RdDActorSheet extends ActorSheet {
RdDItemArme.computeNiveauArmes(formData.combat, formData.competences);
RdDItemArme.ajoutCorpsACorps(formData.combat, formData.competences, formData.data.carac);
formData.esquives = this.actor.getCompetences("Esquive").map(i => foundry.utils.deepClone(i.data));
formData.combat = RdDCombatManager.finalizeArmeList(formData.combat, formData.competences, formData.data.carac);
formData.combat = RdDCombatManager.listActionsArmes(formData.combat, formData.competences, formData.data.carac);
this.armesList = formData.combat;
@@ -335,8 +335,8 @@ export class RdDActorSheet extends ActorSheet {
html.find('.arme-initiative a').click(async event => {
let combatant = game.combat.data.combatants.find(c => c.actor.data._id == this.actor.data._id);
if (combatant) {
let arme = this._getEventArmeCombat(event);
RdDCombatManager.rollInitiativeCompetence(combatant._id, arme);
let action = this._getEventArmeCombat(event);
RdDCombatManager.rollInitiativeAction(combatant._id, action);
} else {
ui.notifications.info("Impossible de lancer l'initiative sans être dans un combat.");
}

View File

@@ -33,7 +33,8 @@ import { RollDataAjustements } from "./rolldata-ajustements.js";
import { DialogItemAchat } from "./dialog-item-achat.js";
import { RdDItem } from "./item.js";
import { RdDPossession } from "./rdd-possession.js";
import { SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { ENTITE_BLURETTE, ENTITE_INCARNE, ENTITE_NONINCARNE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
/* -------------------------------------------- */
/**
@@ -98,7 +99,6 @@ export class RdDActor extends Actor {
* @param {Object} options (Unused) Additional options which customize the creation workflow.
*
*/
static async create(actorData, options) {
// Case of compendium global import
if (actorData instanceof Array) {
@@ -115,11 +115,14 @@ export class RdDActor extends Actor {
return actor;
}
const competences = await RdDUtility.loadCompendium(RdDItemCompetence.actorCompendium(actorData.type));
actorData.items = competences.map(i => i.toObject());
if (isPersonnage) {
const competences = await RdDUtility.loadCompendium(RdDItemCompetence.actorCompendium(actorData.type));
actorData.items = competences.map(i => i.toObject());
actorData.items = actorData.items.concat(Monnaie.monnaiesData());
}
else {
actorData.items = [];
}
return super.create(actorData, options);
}
@@ -132,13 +135,6 @@ export class RdDActor extends Actor {
this.encTotal = 0;
this.prixTotalEquipement = 0;
/*
// Auto-resize token
if (this.isToken) {
let tokenSize = actorData.data.carac.taille.value/10;
this.token.update({height: tokenSize, width: tokenSize } );
}*/
// Make separate methods for each Actor type (character, npc, etc.) to keep
// things organized.
if (actorData.type === 'personnage') this._prepareCharacterData(actorData);
@@ -244,7 +240,7 @@ export class RdDActor extends Actor {
}
/* -------------------------------------------- */
getForce() {
if (this.isEntiteCauchemar()) {
if (this.isEntite()) {
return Misc.toInt(Misc.templateData(this).carac.reve?.value);
}
return Misc.toInt(Misc.templateData(this).carac.force?.value);
@@ -372,12 +368,30 @@ export class RdDActor extends Actor {
const list = this.getDraconicList();
return duplicate(list[0]);
}
getDraconicOrZero() {
const list = this.getDraconicList().filter(it => Misc.data(it).data.niveau >= 0);
if (list.length == 0) {
return { name: "Aucun", data: { niveau: 0 } };
getDraconicOuPossession() {
const possessions = this.items.filter(it => Misc.data(it).type == 'competencecreature' && Misc.templateData(it).ispossession)
.sort(Misc.descending(it => Misc.templateData(it).niveau));
if (possessions.length>0) {
return duplicate(possessions[0]);
}
return duplicate(list[0]);
const draconics = this.getDraconicList().filter(it => Misc.data(it).data.niveau >= 0);
if (draconics.length> 0) {
return duplicate(draconics[0]);
}
return {
img: 'systems/foundryvtt-reve-de-dragon/icons/entites/possession.webp',
name: 'Sans draconic',
data: {
niveau: 0,
defaut_carac: "reve",
}
};
}
getPossession(possessionId) {
return this.items.find(it => it.type == 'possession' && it.data.data.possessionid == possessionId);
}
getPossessions() {
return this.items.filter(it => it.type == 'possession');
}
getDemiReve() {
@@ -599,7 +613,10 @@ export class RdDActor extends Actor {
content: "Remise à neuf de " + this.name
};
const actorData = Misc.data(this);
if (this.isEntiteCauchemar()) {
if (this.isEntite([ENTITE_NONINCARNE])) {
return;
}
if (this.isEntite([ENTITE_INCARNE, ENTITE_BLURETTE])) {
await this.santeIncDec("endurance", actorData.data.sante.endurance.max - actorData.data.sante.endurance.value);
}
else {
@@ -783,7 +800,7 @@ export class RdDActor extends Actor {
async combattreReveDeDragon(force) {
let rollData = {
actor: this,
competence: duplicate(this.getDraconicOrZero()),
competence: duplicate(this.getDraconicOuPossession()),
canClose: false,
rencontre: duplicate(TMRRencontres.getRencontre('rdd')),
tmr: true,
@@ -1609,7 +1626,7 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
async setSonne(sonne = true) {
if (this.isEntiteCauchemar()) {
if (this.isEntite()) {
return;
}
if (!game.combat && sonne) {
@@ -1621,7 +1638,7 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
getSConst() {
if (this.isEntiteCauchemar()) {
if (this.isEntite()) {
return 0;
}
return RdDCarac.calculSConst(Misc.templateData(this).carac.constitution.value);
@@ -1738,7 +1755,7 @@ export class RdDActor extends Actor {
result.newValue = Math.max(minValue, Math.min(compteur.value + inc, compteur.max));
//console.log("New value ", inc, minValue, result.newValue);
let fatigue = 0;
if (name == "endurance" && !this.isEntiteCauchemar()) {
if (name == "endurance" && !this.isEntite()) {
if (result.newValue == 0 && inc < 0 && !isCritique) { // perte endurance et endurance devient 0 (sauf critique) -> -1 vie
sante.vie.value--;
result.perteVie = true;
@@ -1775,7 +1792,7 @@ export class RdDActor extends Actor {
}
isDead() {
return !this.isEntiteCauchemar() && Misc.templateData(this).sante.vie.value < -this.getSConst()
return !this.isEntite() && Misc.templateData(this).sante.vie.value < -this.getSConst()
}
/* -------------------------------------------- */
@@ -2538,9 +2555,9 @@ export class RdDActor extends Actor {
if (rollData.competence.type == 'competencecreature') {
if (rollData.competence.data.iscombat) {
if (rollData.competence.data.ispossession) {
RdDPossession.managePossession(this, rollData.competence)
RdDPossession.onAttaquePossession(this, rollData.competence)
} else {
const arme = RdDItemCompetenceCreature.toArme(rollData.competence)
const arme = RdDItemCompetenceCreature.toActionArme(rollData.competence)
RdDCombat.createUsingTarget(this)?.attaque(competence, arme)
}
return
@@ -2566,8 +2583,8 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
conjurerPossession(possession) {
let draconic = this.getBestDraconic();
RdDPossession.managePossession(this, draconic, possession)
let draconic = this.getDraconicOuPossession();
RdDPossession.onAttaquePossession(this, draconic, possession)
}
/* -------------------------------------------- */
@@ -3130,7 +3147,7 @@ export class RdDActor extends Actor {
return carac.chance;
}
let entry = Misc.findFirstLike(name, Object.entries(carac), { mapper: it => it[1].label, description: 'caractéristique' });
return entry.length > 0 ? carac[entry[0]] : undefined;
return entry && entry.length > 0 ? carac[entry[0]] : undefined;
}
/* -------------------------------------------- */
@@ -3206,7 +3223,7 @@ export class RdDActor extends Actor {
let competence = Misc.data(this.getCompetence(arme.data.competence));
if (arme || (competence.type == 'competencecreature' && competence.data.iscombat)) {
if (competence.data.ispossession) {
RdDPossession.managePossession(this, competence);
RdDPossession.onAttaquePossession(this, competence);
} else {
RdDCombat.createUsingTarget(this)?.attaque(competence, arme);
}
@@ -3334,7 +3351,7 @@ export class RdDActor extends Actor {
let encaissement = await this.jetEncaissement(rollData);
this.ajouterBlessure(encaissement); // Will upate the result table
const perteVie = this.isEntiteCauchemar()
const perteVie = this.isEntite()
? { newValue: 0 }
: await this.santeIncDec("vie", - encaissement.vie);
const perteEndurance = await this.santeIncDec("endurance", -encaissement.endurance, encaissement.critiques > 0);
@@ -3349,7 +3366,7 @@ export class RdDActor extends Actor {
sonne: perteEndurance.sonne,
jetEndurance: perteEndurance.jetEndurance,
endurance: santeOrig.endurance.value - perteEndurance.newValue,
vie: this.isEntiteCauchemar() ? 0 : (santeOrig.vie.value - perteVie.newValue),
vie: this.isEntite() ? 0 : (santeOrig.vie.value - perteVie.newValue),
show: defenderRoll?.show ?? {}
});
@@ -3539,8 +3556,8 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
async accorder(entite, when = 'avant-encaissement') {
if (when != game.settings.get(SYSTEM_RDD, "accorder-entite-cauchemar")
|| !entite.isEntiteCauchemar()
|| entite.isEntiteCauchemarAccordee(this)) {
|| !entite.isEntite([ENTITE_INCARNE])
|| entite.isEntiteAccordee(this)) {
return true;
}
const tplData = Misc.templateData(this);
@@ -3564,29 +3581,30 @@ export class RdDActor extends Actor {
}
/* -------------------------------------------- */
isEntiteCauchemar() {
return this.data.type == 'entite';
isEntite(typeentite = [] ) {
return this.data.type == 'entite' && (typeentite.length == 0 || typeentite.includes(this.data.data.typeentite));
}
/* -------------------------------------------- */
isEntiteCauchemarAccordee(attaquant) {
if (!this.isEntiteCauchemar()) { return true; }
isEntiteAccordee(attaquant) {
if (!this.isEntite([ENTITE_INCARNE]))
{ return true; }
let resonnance = Misc.templateData(this).sante.resonnance;
return (resonnance.actors.find(it => it == attaquant._id));
return (resonnance.actors.find(it => it == attaquant.id));
}
/* -------------------------------------------- */
async setEntiteReveAccordee(attaquant) {
if (!this.isEntiteCauchemar()) {
if (!this.isEntite([ENTITE_INCARNE])) {
ui.notifications.error("Impossible de s'accorder à " + this.name + ": ce n'est pas une entite de cauchemer/rêve");
return;
}
let resonnance = duplicate(Misc.templateData(this).sante.resonnance);
if (resonnance.actors.find(it => it == attaquant._id)) {
if (resonnance.actors.find(it => it == attaquant.id)) {
// déjà accordé
return;
}
resonnance.actors.push(attaquant._id);
resonnance.actors.push(attaquant.id);
await this.update({ "data.sante.resonnance": resonnance });
return;
}
@@ -4140,7 +4158,7 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
async setStatusEffect(label, status, updates = {}) {
if (this.isEntiteCauchemar() || this.data.type == 'vehicule') {
if (this.isEntite() || this.data.type == 'vehicule') {
return;
}
console.log("setStatusEffect", label, status, updates)

View File

@@ -3,3 +3,7 @@ export const SYSTEM_SOCKET_ID = 'system.foundryvtt-reve-de-dragon';
export const HIDE_DICE = 'hide';
export const SHOW_DICE = 'show';
export const ENTITE_INCARNE = 'incarne';
export const ENTITE_NONINCARNE = 'nonincarne';
export const ENTITE_BLURETTE = 'blurette';

View File

@@ -55,7 +55,7 @@ export class DialogItemAchat extends Dialog {
static prepareVenteData(buttonAcheter, vendeurId, vendeur, acheteur) {
const jsondata = buttonAcheter.attributes['data-jsondata']?.value;
const prixLot = buttonAcheter.attributes['data-prixLot']?.value ?? 0;
const prixLot = parseInt(buttonAcheter.attributes['data-prixLot']?.value ?? 0);
let venteData = {
item: JSON.parse(jsondata),
vendeurId: vendeurId,

View File

@@ -30,7 +30,7 @@ export class RdDItemArme extends Item {
switch (armeData ? armeData.type : '') {
case 'arme': return armeData;
case 'competencecreature':
return RdDItemCompetenceCreature.toArme(armeData);
return RdDItemCompetenceCreature.toActionArme(armeData);
}
return RdDItemArme.mainsNues();
}
@@ -189,7 +189,7 @@ export class RdDItemArme extends Item {
categorie_parade: 'sans-armes'
}
};
mergeObject(corpsACorps.data, actorData ??{}, { overwrite: false });
mergeObject(corpsACorps.data, actorData ?? {}, { overwrite: false });
return corpsACorps;
}

View File

@@ -212,8 +212,11 @@ export class RdDItemCompetence extends Item {
/* -------------------------------------------- */
static findCompetence(list, idOrName, options = {}) {
if (idOrName == undefined) {
return undefined;
}
options = mergeObject(options, {
filter: it => RdDItemCompetence.isCompetence(it),
preFilter: it => RdDItemCompetence.isCompetence(it),
description: 'compétence',
});
return list.find(it => it.id == idOrName && RdDItemCompetence.isCompetence(it))

View File

@@ -11,14 +11,14 @@ export class RdDItemCompetenceCreature extends Item {
rollData.competence.data.categorie = "creature"
rollData.selectedCarac = rollData.carac.carac_creature
if (rollData.competence.data.iscombat) {
rollData.arme = RdDItemCompetenceCreature.toArme(rollData.competence);
rollData.arme = RdDItemCompetenceCreature.toActionArme(rollData.competence);
}
}
/* -------------------------------------------- */
static toArme(item) {
static toActionArme(item) {
if (RdDItemCompetenceCreature.isCompetenceAttaque(item)) {
// si c'est un Item compétence: cloner pour ne pas modifier lma compétence
// si c'est un Item compétence: cloner pour ne pas modifier la compétence
let arme = Misc.data( (item instanceof Item) ? item.clone(): item);
mergeObject(arme.data,
{
@@ -28,11 +28,12 @@ export class RdDItemCompetenceCreature extends Item {
dommagesReels: arme.data.dommages,
penetration: 0,
force: 0,
rapide: true
rapide: true,
action: 'attaque'
});
return arme;
}
console.error("RdDItemCompetenceCreature.toArme(", item, ") : impossible de transformer l'Item en arme");
console.error("RdDItemCompetenceCreature.toActionArme(", item, ") : impossible de transformer l'Item en arme");
return undefined;
}

View File

@@ -192,7 +192,7 @@ export class Misc {
if (!single) {
single = subset[0];
const choices = Misc.join(subset.map(it => options.mapper(it)), '<br>');
options.info(`Plusieurs choix de ${options.description}s possibles:<br>${choices}<br>Le premier sera choisi: ${mapToValue(single)}`);
options.onMessage(`Plusieurs choix de ${options.description}s possibles:<br>${choices}<br>Le premier sera choisi: ${options.mapper(single)}`);
}
return single;
}
@@ -211,7 +211,7 @@ export class Misc {
}
value = Grammar.toLowerCaseNoAccent(value);
const subset = elements.filter(options.preFilter)
.filter(it => Grammar.toLowerCaseNoAccent(options.mapper(it)).includes(value));
.filter(it => Grammar.toLowerCaseNoAccent(options.mapper(it))?.includes(value));
if (subset.length == 0) {
options.onMessage(`Pas de ${options.description} correspondant à ${value}`);
}

View File

@@ -1,5 +1,6 @@
import { ChatUtility } from "./chat-utility.js";
import { HIDE_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { ENTITE_INCARNE, ENTITE_NONINCARNE, HIDE_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { Grammar } from "./grammar.js";
import { RdDItemArme } from "./item-arme.js";
import { RdDItemCompetence } from "./item-competence.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
@@ -26,7 +27,7 @@ const premierRoundInit = [
{ pattern: 'epeegnome', init: 5.35 },
{ pattern: 'masse', init: 5.30 },
{ pattern: 'gourdin', init: 5.25 },
{ pattern: 'fléau', init: 5.20 },
{ pattern: 'fleau', init: 5.20 },
{ pattern: 'dague', init: 5.15 },
{ pattern: 'autre', init: 5.10 },
];
@@ -84,28 +85,23 @@ export class RdDCombatManager extends Combat {
// calculate initiative
for (let cId = 0; cId < ids.length; cId++) {
const combatant = this.combatants.get(ids[cId]);
//if (!c) return results;
let rollFormula = formula; // Init per default
if (!rollFormula) {
let armeCombat, competence;
let rollFormula = formula ?? RdDCombatManager.formuleInitiative(2, 10, 0, 0);
if (!formula) {
if (combatant.actor.data.type == 'creature' || combatant.actor.data.type == 'entite') {
for (const competenceItemData of combatant.actor.data.items) {
if (competenceItemData.data.data.iscombat) {
competence = duplicate(competenceItemData);
}
const competence = combatant.actor.data.items.find(it => it.data.data.iscombat)
if (competence) {
rollFormula = RdDCombatManager.formuleInitiative(2, competence.data.carac_value, competence.data.niveau, 0);
}
rollFormula = "2+( (" + RdDCombatManager.calculInitiative(competence.data.niveau, competence.data.carac_value) + ")/100)";
} else {
for (const itemData of combatant.actor.data.items) {
if (itemData.type == "arme" && itemData.data.equipe) {
armeCombat = duplicate(itemData);
}
const armeCombat = combatant.actor.data.items.find(it => it.type == 'arme' && itemData.data.equipe)
const compName = (armeCombat == undefined) ? "Corps à corps" : armeCombat.data.competence;
const competence = RdDItemCompetence.findCompetence(combatant.actor.data.items, compName);
if (competence) {
const carac = combatant.actor.data.data.carac[competence.data.defaut_carac].value;
const niveau = competence.data.niveau;
const bonusEcaille = (armeCombat?.data.magique) ? armeCombat.data.ecaille_efficacite : 0;
rollFormula = RdDCombatManager.formuleInitiative(2, carac, niveau, bonusEcaille);
}
let compName = (armeCombat == undefined) ? "Corps à corps" : armeCombat.data.competence;
competence = RdDItemCompetence.findCompetence(combatant.actor.data.items, compName);
let bonusEcaille = (armeCombat && armeCombat.data.magique) ? armeCombat.data.ecaille_efficacite : 0;
rollFormula = "2+( (" + RdDCombatManager.calculInitiative(competence.data.niveau, Misc.data(combatant.actor).data.carac[competence.data.defaut_carac].value, bonusEcaille) + ")/100)";
}
}
//console.log("Combatat", c);
@@ -142,6 +138,10 @@ export class RdDCombatManager extends Combat {
return this;
};
static formuleInitiative(rang, carac, niveau, bonusMalus) {
return `${rang} +( (${RdDCombatManager.calculInitiative(niveau, carac, bonusMalus)} )/100)`;
}
/* -------------------------------------------- */
static calculInitiative(niveau, caracValue, bonusEcaille = 0) {
let base = niveau + Math.floor(caracValue / 2);
@@ -150,63 +150,77 @@ export class RdDCombatManager extends Combat {
}
/* -------------------------------------------- */
/** Retourne une liste triée d'armes avec le split arme1 main / arme 2 main */
static finalizeArmeList(armes, competences, carac) {
/** Retourne une liste triée d'actions d'armes avec le split arme1 main / arme 2 main */
static listActionsArmes(armes, competences, carac) {
// Gestion des armes 1/2 mains
let armesEquipe = [];
let actionsArme = [];
for (const arme of armes) {
let armeData = duplicate(Misc.data(arme));
if (armeData.data.equipe) {
let compData = competences.map(c => Misc.data(c)).find(c => c.name == armeData.data.competence);
let action = duplicate(Misc.data(arme));
if (action.data.equipe) {
let compData = competences.map(c => Misc.data(c)).find(c => c.name == action.data.competence);
armesEquipe.push(armeData);
armeData.data.dommagesReels = Number(armeData.data.dommages);
armeData.data.niveau = compData.data.niveau;
armeData.data.initiative = RdDCombatManager.calculInitiative(compData.data.niveau, carac[compData.data.defaut_carac].value);
actionsArme.push(action);
action.action = 'attaque';
action.data.dommagesReels = Number(action.data.dommages);
action.data.niveau = compData.data.niveau;
action.data.initiative = RdDCombatManager.calculInitiative(compData.data.niveau, carac[compData.data.defaut_carac].value);
// Dupliquer les armes pouvant être à 1 main et 2 mains en patchant la compétence
if (armeData.data.unemain && !armeData.data.deuxmains) {
armeData.data.mainInfo = "(1m)";
} else if (!armeData.data.unemain && armeData.data.deuxmains) {
armeData.data.mainInfo = "(2m)";
} else if (armeData.data.unemain && armeData.data.deuxmains) {
armeData.data.mainInfo = "(1m)";
if (action.data.unemain && !action.data.deuxmains) {
action.data.mainInfo = "(1m)";
} else if (!action.data.unemain && action.data.deuxmains) {
action.data.mainInfo = "(2m)";
} else if (action.data.unemain && action.data.deuxmains) {
action.data.mainInfo = "(1m)";
const comp2m = armeData.data.competence.replace(" 1 main", " 2 mains"); // Replace !
const comp2m = action.data.competence.replace(" 1 main", " 2 mains"); // Replace !
const comp = Misc.data(competences.find(c => c.name == comp2m));
const arme2main = duplicate(armeData);
const arme2main = duplicate(action);
arme2main.data.mainInfo = "(2m)";
arme2main.data.niveau = comp.data.niveau;
arme2main.data.competence = comp2m;
arme2main.data.initiative = RdDCombatManager.calculInitiative(arme2main.data.niveau, carac[comp.data.defaut_carac].value);
armesEquipe.push(arme2main);
const containsSlash = armeData.data.dommages.includes("/");
actionsArme.push(arme2main);
const containsSlash = action.data.dommages.includes("/");
if (containsSlash) {
const tableauDegats = armeData.data.dommages.split("/");
armeData.data.dommagesReels = Number(tableauDegats[0]);
const tableauDegats = action.data.dommages.split("/");
action.data.dommagesReels = Number(tableauDegats[0]);
arme2main.data.dommagesReels = Number(tableauDegats[1]);
}
else{
ui.notifications.info("Les dommages de l'arme à 1/2 mains " + armeData.name + " ne sont pas corrects (ie sous la forme X/Y)");
ui.notifications.info("Les dommages de l'arme à 1/2 mains " + action.name + " ne sont pas corrects (ie sous la forme X/Y)");
}
}
}
}
return armesEquipe.sort(Misc.ascending(armeData => armeData.name + (armeData.data.mainInfo ?? '')));
return actionsArme.sort(Misc.ascending(armeData => armeData.name + (armeData.data.mainInfo ?? '')));
}
static listActionsPossessions(actor) {
return RdDCombatManager._indexActions(actor.getPossessions().map(p =>
{
return {
name: p.name,
action: 'conjurer',
data: {
competence: p.name,
possessionid: p.data.data.possessionid,
}
}
}));
}
/* -------------------------------------------- */
static buildListeActionsCombat(combatant) {
if (combatant.actor == undefined) {
ui.notifications.warn(`Le combatant ${combatant.name} n'est pas associé à un acteur, impossible de déterminer ses actions de combat!`)
return [];
static listActionsCombat(combatant) {
const actor = combatant.actor;
let actions = RdDCombatManager.listActionsPossessions(actor);
if (actions.length>0) {
return actions;
}
const actorData = Misc.data(combatant.actor);
let items = combatant.actor.data.items;
let actions = []
if (combatant.actor.isCreature()) {
let items = actor.data.items;
if (actor.isCreature()) {
actions = actions.concat(items.filter(it => RdDItemCompetenceCreature.isCompetenceAttaque(it))
.map(competence => RdDItemCompetenceCreature.toArme(competence)));
.map(competence => RdDItemCompetenceCreature.toActionArme(competence)));
} else {
// Recupération des items 'arme'
let armes = items.filter(it => RdDItemArme.isArmeUtilisable(it))
@@ -214,14 +228,17 @@ export class RdDCombatManager extends Combat {
.concat(RdDItemArme.mainsNues());
let competences = items.filter(it => it.type == 'competence');
actions = actions.concat(RdDCombatManager.finalizeArmeList(armes, competences, actorData.data.carac));
actions = actions.concat(RdDCombatManager.listActionsArmes(armes, competences, actor.data.data.carac));
if (actorData.data.attributs.hautrevant.value) {
actions.push({ name: "Draconic", data: { initOnly: true, competence: "Draconic" } });
if (actor.data.data.attributs.hautrevant.value) {
actions.push({ name: "Draconic", action: 'haut-reve', data: { initOnly: true, competence: "Draconic" } });
}
}
actions.push({ name: "Autre action", data: { initOnly: true, competence: "Autre action" } });
return RdDCombatManager._indexActions(actions);
}
static _indexActions(actions) {
for (let index = 0; index < actions.length; index++) {
actions[index].index = index;
}
@@ -235,15 +252,15 @@ export class RdDCombatManager extends Combat {
let initMissing = game.combat.data.combatants.find(it => !it.initiative);
if (!initMissing) { // Premier round !
for (let combatant of game.combat.data.combatants) {
let arme = combatant.initiativeData?.arme;
let action = combatant.initiativeData?.arme;
//console.log("Parsed !!!", combatant, initDone, game.combat.current, arme);
if (arme && arme.type == "arme") {
if (action && action.type == "arme") {
for (let initData of premierRoundInit) {
if (arme.data.initpremierround.toLowerCase().includes(initData.pattern)) {
if (Grammar.toLowerCaseNoAccentNoSpace(action.data.initpremierround).includes(initData.pattern)) {
let msg = `<h4>L'initiative de ${combatant.actor.name} a été modifiée !</h4>
<hr>
<div>
Etant donné son ${arme.name}, son initative pour ce premier round est désormais de ${initData.init}.
Etant donné son ${action.name}, son initative pour ce premier round est désormais de ${initData.init}.
</div>`
ChatMessage.create({ content: msg });
game.combat.setInitiative(combatant._id, initData.init);
@@ -281,7 +298,7 @@ export class RdDCombatManager extends Combat {
].concat(options);
}
/* -------------------------------------------- */
static rollInitiativeCompetence(combatantId, arme) {
static rollInitiativeAction(combatantId, action) {
const combatant = game.combat.combatants.get(combatantId);
if (combatant.actor == undefined) {
ui.notifications.warn(`Le combatant ${combatant.name} n'est pas associé à un acteur, impossible de déterminer ses actions de combat!`)
@@ -299,34 +316,40 @@ export class RdDCombatManager extends Combat {
} else if (combatant.actor.getSurprise() == "demi") {
initOffset = 0;
initInfo = "Demi Surprise"
} else if (arme.name == "Autre action") {
} else if (action.action == 'conjurer') {
initOffset = 10;
caracForInit = combatant.actor.getReveActuel();
initInfo = "Possession"
} else if (action.action == 'autre') {
initOffset = 2;
initInfo = "Autre Action"
} else if (arme.name == "Draconic") {
} else if (action.action == 'haut-reve') {
initOffset = 9;
initInfo = "Draconic"
} else {
compData = Misc.data(RdDItemCompetence.findCompetence(combatant.actor.data.items, arme.data.competence));
compData = Misc.data(RdDItemCompetence.findCompetence(combatant.actor.data.items, action.data.competence));
compNiveau = compData.data.niveau;
initInfo = arme.name + " / " + arme.data.competence;
if (combatant.actor.data.type == 'creature' || combatant.actor.data.type == 'entite') {
caracForInit = compData.data.carac_value;
if (compData.data.categorie == "lancer") {
initOffset = 7;
}
else {
initOffset = 5;
}
} else {
caracForInit = Misc.data(combatant.actor).data.carac[compData.data.defaut_carac].value;
initOffset = RdDCombatManager._baseInitOffset(compData.data.categorie, arme);
initInfo = action.name + " / " + action.data.competence;
if (combatant.actor.data.type == 'creature' || combatant.actor.data.type == 'entite') {
caracForInit = compData.data.carac_value;
if (compData.data.categorie == "lancer") {
initOffset = 7;
}
else {
initOffset = 5;
}
} else {
caracForInit = Misc.data(combatant.actor).data.carac[compData.data.defaut_carac].value;
initOffset = RdDCombatManager._baseInitOffset(compData.data.categorie, action);
}
}
let malus = combatant.actor.getEtatGeneral(); // Prise en compte état général
// Cas des créatures et entités vs personnages
let rollFormula = initOffset + "+ ( (" + RdDCombatManager.calculInitiative(compNiveau, caracForInit) + " + " + malus + ") /100)";
let rollFormula = RdDCombatManager.formuleInitiative(initOffset, caracForInit, compNiveau, malus);
// Garder la trace de l'arme/compétence utilisée pour l'iniative
combatant.initiativeData = { arme: arme } // pour reclasser l'init au round 0
combatant.initiativeData = { arme: action } // pour reclasser l'init au round 0
game.combat.rollInitiative(combatantId, rollFormula, { initInfo: initInfo });
}
@@ -349,16 +372,21 @@ export class RdDCombatManager extends Combat {
static displayInitiativeMenu(html, combatantId) {
console.log("Combatant ; ", combatantId);
const combatant = game.combat.combatants.get(combatantId);
let armesList = RdDCombatManager.buildListeActionsCombat(combatant);
if (! (combatant?.actor) ) {
ui.notifications.warn(`Le combatant ${combatant.name ?? combatantId} n'est pas associé à un acteur, impossible de déterminer ses actions de combat!`)
return;
}
let actions = RdDCombatManager.listActionsCombat(combatant);
// Build the relevant submenu
if (armesList) {
if (actions) {
let menuItems = [];
for (let arme of armesList) {
for (let action of actions) {
menuItems.push({
name: arme.data.competence,
name: action.data.competence,
icon: "<i class='fas fa-dice-d6'></i>",
callback: target => { RdDCombatManager.rollInitiativeCompetence(combatantId, arme) }
callback: target => { RdDCombatManager.rollInitiativeAction(combatantId, action) }
});
}
new ContextMenu(html, ".directory-list", menuItems).render();
@@ -429,7 +457,7 @@ export class RdDCombat {
else {
const defender = target?.actor;
const defenderTokenId = target?.data._id;
if ( defender.type == 'entite' && defender.data.data.definition.typeentite == 'nonincarne') {
if ( defender.type == 'entite' && defender.data.data.definition.typeentite == ENTITE_NONINCARNE) {
ui.notifications.warn("Vous ne pouvez pas cibler une entité non incarnée !!!!");
} else {
return this.create(attacker, defender, defenderTokenId, target)
@@ -771,7 +799,7 @@ export class RdDCombat {
async _onAttaqueNormale(attackerRoll) {
console.log("RdDCombat.onAttaqueNormale >>>", attackerRoll);
attackerRoll.dmg = RdDBonus.dmg(attackerRoll, this.attacker.getBonusDegat(), this.defender.isEntiteCauchemar());
attackerRoll.dmg = RdDBonus.dmg(attackerRoll, this.attacker.getBonusDegat(), this.defender.isEntite());
let defenderRoll = { attackerRoll: attackerRoll, passeArme: attackerRoll.passeArme, show: {} }
attackerRoll.show = {
cible: this.target ? this.defender.data.name : 'la cible',
@@ -1221,8 +1249,8 @@ export class RdDCombat {
async accorderEntite(when = 'avant-encaissement') {
if (when != game.settings.get(SYSTEM_RDD, "accorder-entite-cauchemar")
|| this.defender == undefined
|| !this.defender.isEntiteCauchemar()
|| this.defender.isEntiteCauchemarAccordee(this.attacker)) {
|| !this.defender.isEntite([ENTITE_INCARNE])
|| this.defender.isEntiteAccordee(this.attacker)) {
return true;
}

View File

@@ -276,9 +276,11 @@ export class RdDCommands {
diff = 0;
}
const caracName = params[0];
const compName = length > 1 ? Misc.join(params.slice(1, length), ' ') : undefined;
for (let actor of actors) {
await actor.rollCaracCompetence(caracName, compName, diff);
let competence = length > 1 ? actors[0].getCompetence(Misc.join(params.slice(1, length), ' ')) : undefined;
if (competence) {
for (let actor of actors) {
await actor.rollCaracCompetence(caracName, competence.name, diff);
}
}
return;
}

View File

@@ -1,19 +1,29 @@
import { RdDActor } from "./actor.js";
import { Misc } from "./misc.js";
import { RdDDice } from "./rdd-dice.js";
const words = [ 'pore', 'pre', 'flor', 'lane', 'turlu', 'pin', 'a', 'alph', 'i', 'onse', 'iane', 'ane', 'zach', 'arri', 'ba', 'bo', 'bi',
'alta', 'par', 'pir', 'zor', 'zir', 'de', 'pol', 'tran', 'no', 'la', 'al' , 'pul', 'one', 'ner', 'nur', 'mac', 'mery',
'cat', 'do', 'di', 'der', 'er', 'el', 'far', 'fer', 'go', 'guer', 'hot', 'jor', 'jar', 'ji', 'kri', 'ket', 'lor', 'hur',
'lar', 'lir', 'lu', 'pot', 'pro', 'pra', 'pit', 'qua', 'qui', 're', 'ral', 'sal', 'sen', 'ted', 'to', 'ta', 'lars', 'ver',
'vin', 'ov', 'wal', 'ry', 'ly', '' ];
const words = ['pore', 'pre', 'flor', 'lane', 'turlu', 'pin', 'a', 'alph', 'i', 'onse', 'iane', 'ane', 'zach', 'arri', 'ba', 'bo', 'bi',
'alta', 'par', 'pir', 'zor', 'zir', 'de', 'pol', 'tran', 'no', 'la', 'al', 'pul', 'one', 'ner', 'nur', 'mac', 'mery',
'cat', 'do', 'di', 'der', 'er', 'el', 'far', 'fer', 'go', 'guer', 'hot', 'jor', 'jar', 'ji', 'kri', 'ket', 'lor', 'hur',
'lar', 'lir', 'lu', 'pot', 'pro', 'pra', 'pit', 'qua', 'qui', 're', 'ral', 'sal', 'sen', 'ted', 'to', 'ta', 'lars', 'ver',
'vin', 'ov', 'wal', 'ry', 'ly', ''];
/* -------------------------------------------- */
export class RdDNameGen {
static async getName( msg, params ) {
let name = Misc.upperFirst( await RdDDice.rollOneOf(words) + await RdDDice.rollOneOf(words) )
//console.log(name);
ChatMessage.create( { content: `Nom : ${name}`, whisper: ChatMessage.getWhisperRecipients("GM") } );
static async getName(msg, params) {
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-command-nom.html`, {
nom: Misc.upperFirst(await RdDDice.rollOneOf(words) + await RdDDice.rollOneOf(words))
});
ChatMessage.create({ content: html, whisper: ChatMessage.getWhisperRecipients("GM") });
}
static async onCreerActeur(event) {
const button = event.currentTarget;
await RdDActor.create({
name: button.attributes['data-nom'].value,
type: button.attributes['data-type'].value
},
{renderSheet: true});
}
}

View File

@@ -14,44 +14,44 @@ Donc la compétence Possession ne peut être démarrée que par le MJ.
export class RdDPossession {
/* -------------------------------------------- */
static init() {
static init() {
}
/* -------------------------------------------- */
static searchPossessionFromEntite( attacker, defender) {
let poss = attacker.data.items.find( poss => poss.type == 'possession' && poss.data.data.possedeid == defender.data._id);
static searchPossessionFromEntite(attacker, defender) {
let poss = attacker.data.items.find(poss => poss.type == 'possession' && poss.data.data.possedeid == defender.data._id);
if (!poss) {
poss = defender.data.items.find( poss => poss.type == 'possession' && poss.data.data.possedeid == defender.data._id);
poss = defender.data.items.find(poss => poss.type == 'possession' && poss.data.data.possedeid == defender.data._id);
}
return poss && duplicate(poss) || undefined;
}
/* -------------------------------------------- */
static updateEtatPossession( possession ) {
static updateEtatPossession(possession) {
possession.ptsConjuration = 0
possession.ptsPossession = 0
console.log("Possession", possession)
if ( possession.data.compteur > 0) {
if (possession.data.compteur > 0) {
possession.ptsPossession = possession.data.compteur
}
if ( possession.data.compteur < 0) {
}
if (possession.data.compteur < 0) {
possession.ptsConjuration = Math.abs(possession.data.compteur)
}
}
possession.isPosseder = false
possession.isConjurer = false
if (possession.ptsPossession >= 2 ) {
if (possession.ptsPossession >= 2) {
possession.isPosseder = true
}
if (possession.ptsConjuration >= 2 ) {
if (possession.ptsConjuration >= 2) {
possession.isConjurer = true
}
}
/* -------------------------------------------- */
static async resultConjuration( rollData) {
static async resultConjuration(rollData) {
let actor = game.actors.get(rollData.possession.data.possedeid)
if ( !rollData.rolled.isSuccess ) {
if( rollData.isECNIDefender) {
if (!rollData.rolled.isSuccess) {
if (rollData.isECNIDefender) {
rollData.possession.data.compteur--
} else {
rollData.possession.data.compteur++
@@ -59,55 +59,41 @@ export class RdDPossession {
let update = { _id: rollData.possession._id, "data.compteur": rollData.possession.data.compteur }
await actor.updateEmbeddedDocuments('Item', [update])
}
this.updateEtatPossession(rollData.possession)
await RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-possession.html')
if ( rollData.possession.isPosseder || rollData.possession.isConjurer) {
if (rollData.possession.isPosseder || rollData.possession.isConjurer) {
actor.deleteEmbeddedDocuments("Item", [rollData.possession._id])
}
}
/* -------------------------------------------- */
static async onDefensePossession( attackerId, defenderId, possessionId) {
static async onDefensePossession(attackerId, defenderId, possessionId) {
let attacker = game.actors.get(attackerId)
let defender = game.actors.get(defenderId)
let possession = attacker.items.find( item => item.type =='possession' && item.data.data.possessionid == possessionId)
if ( !possession ) {
possession = defender.items.find( item => item.type =='possession' && item.data.data.possessionid == possessionId)
if ( !possession) {
ui.notifications.warn("Une erreur s'est produite : Aucune possession trouvée !!")
return
}
let possession = attacker.getPossession(possessionId) ?? defender.getPossession(possessionId) ;
if (!possession) {
ui.notifications.warn("Une erreur s'est produite : Aucune possession trouvée !!")
return
}
possession = duplicate(possession)
// Update for draconic roll
let rollData = {
possession: possession
mode: "conjuration",
isECNIDefender: defender.type == "entite",
possession: duplicate(possession),
attacker: attacker,
defender: defender,
competence: defender.getDraconicOuPossession(),
selectedCarac: defender.data.data.carac.reve,
forceCarac: { 'reve-actuel': { label: "Rêve Actuel", value: defender.getReveActuel() } }
}
rollData.actor = defender
if ( defender.type == "personnage") {
rollData.competence = duplicate(defender.getDraconicOrZero())
rollData.competence.data.defaut_carac = 'reve-actuel'
rollData.forceCarac = { 'reve-actuel': { label: "Rêve Actuel", value: defender.getReveActuel() } }
rollData.selectedCarac = defender.data.data.carac.reve
rollData.isECNIDefender = false
} else {
rollData.competence = duplicate(defender.getCompetence("Possession"))
rollData.competence.data.defaut_carac = "reve"
rollData.forceCarac = { 'reve': { label: "Rêve", value: defender.data.data.carac.reve.value } }
rollData.selectedCarac = defender.data.data.carac.reve
rollData.isECNIDefender = true
//RdDItemCompetenceCreature.setRollDataCreature( rollData )
}
rollData.mode = "conjuration"
rollData.possesseur = attacker.name
rollData.competence.data.defaut_carac = 'reve-actuel'
const dialog = await RdDRoll.create(defender, rollData,
{
html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-defense-possession.html',
options: { height: 400 }
options: { height: 450 }
},
{
name: 'conjurer',
@@ -121,54 +107,38 @@ export class RdDPossession {
}
/* -------------------------------------------- */
static async _onRollPossession( rollData, isSuccess ) {
let possession = rollData.possession
possession.isSuccess = isSuccess
this.updateEtatPossession( possession)
await RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-possession.html');
}
/* -------------------------------------------- */
static async managePossession(attacker, competence, possession=undefined) {
static async onAttaquePossession(attacker, competence, possession = undefined) {
const target = RdDCombat.getTarget()
if (target == undefined) {
ui.notifications.warn((game.user.targets?.size ?? 0) > 1
? "Vous devez choisir <strong>une seule</strong> cible à posséder!"
: "Vous devez choisir une cible à posséder!");
return;
}
const defender = target.actor;
if ( !possession) {
possession = this.searchPossessionFromEntite( attacker, defender)
if ( !possession) {
possession = await this.createPossession(attacker, defender)
}
}
possession = duplicate(possession);
const defender = target.actor;
possession = duplicate(possession ?? this.searchPossessionFromEntite(attacker, defender) ??(await this.createPossession(attacker, defender)));
this.updateEtatPossession(possession)
let rollData = {
competence: competence.data.data.niveau >=0 ? competence : RdDPossession.competenceNonHautRevant(),
mode: "possession",
isECNIDefender: defender.type == "entite",
competence: competence,
possession: possession,
possede: defender.name,
possesseur: attacker.name,
attackerId: attacker.data._id,
defenderId: defender.data._id,
mode: "possession"
attacker: attacker,
defender: defender
};
if ( attacker.isCreature()) {
if (attacker.isCreature()) {
RdDItemCompetenceCreature.setRollDataCreature(rollData)
}
const dialog = await RdDRoll.create( attacker, rollData,
const dialog = await RdDRoll.create(attacker, rollData,
{
html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html',
options: { height: 540 }
}, {
name: 'jet-possession',
label: 'Possession: ',
label: rollData.isECNIDefender ? 'Conjurer la possession' : 'Possession',
callbacks: [
{ condition: r => (r.rolled.isSuccess), action: async r => await this._onRollPossession(r, true) },
{ condition: r => (r.rolled.isEchec), action: async r => await this._onRollPossession(r, false) },
@@ -177,21 +147,15 @@ export class RdDPossession {
dialog.render(true)
}
static competenceNonHautRevant() {
return {
img: 'systems/foundryvtt-reve-de-dragon/icons/competence_vigilance.webp',
name: 'non Haut-rêvant',
data: {
data: {
niveau: 0,
defaut_carac: "reve",
}
}
};
/* -------------------------------------------- */
static async _onRollPossession(rollData, isSuccess) {
rollData.possession.isSuccess = isSuccess;
this.updateEtatPossession(rollData.possession);
await RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-possession.html');
}
/* -------------------------------------------- */
static async createPossession( attacker, defender ) {
static async createPossession(attacker, defender) {
let possessionData = {
name: "Possession en cours de " + attacker.name, type: 'possession',
img: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp",

View File

@@ -1,3 +1,5 @@
import { ENTITE_BLURETTE, ENTITE_INCARNE, ENTITE_NONINCARNE } from "./constants";
/**
* Extend the base Dialog entity by defining a custom window to perform roll.
* @extends {Dialog}
@@ -7,15 +9,19 @@ export class RdDEncaisser extends Dialog {
/* -------------------------------------------- */
constructor(html, actor) {
// Common conf
const buttonsCreatures = {
"mortel": { label: "Mortel", callback: html => this.performEncaisser("mortel") },
"non-mortel": { label: "Non-mortel", callback: html => this.performEncaisser("non-mortel") },
"sonne": { label: "Sonné", callback: html => this.actor.setSonne() },
};
const buttonsEntitesCauchemar = {
"cauchemar": { label: "cauchemar", callback: html => this.performEncaisser("cauchemar") }
};
const buttons = actor.isEntiteCauchemar() ? buttonsEntitesCauchemar : buttonsCreatures;
let buttons = {};
if (!actor.isEntite()){
buttons = {
"mortel": { label: "Mortel", callback: html => this.performEncaisser("mortel") },
"non-mortel": { label: "Non-mortel", callback: html => this.performEncaisser("non-mortel") },
"sonne": { label: "Sonné", callback: html => this.actor.setSonne() },
};
}
else if (actor.isEntite([ENTITE_BLURETTE, ENTITE_INCARNE])){
buttons = {
"cauchemar": { label: "cauchemar", callback: html => this.performEncaisser("cauchemar") }
}
}
let dialogConf = {
title: "Jet d'Encaissement",

View File

@@ -23,40 +23,63 @@ export class RdDTokenHud {
let token = canvas.tokens.get(tokenId);
let actor = token.actor;
let combatant = game.combat.combatants.find(c => Misc.data(c).tokenId == tokenId);
if (! (combatant?.actor) ) {
ui.notifications.warn(`Le combatant ${token.name} n'est pas associé à un acteur, impossible de déterminer ses actions de combat!`)
return;
}
app.hasExtension = true;
let armesList = RdDCombatManager.buildListeActionsCombat(combatant);
let actionsCombat = RdDCombatManager.listActionsCombat(combatant);
const hudData = {
combatant: combatant, armes: armesList,
commandes: [{ name: 'Initiative +1', command: 'inc', value: 0.01 }, { name: 'Initiative -1', command: 'dec', value: -0.01 }]
combatant: combatant,
actions: actionsCombat,
commandes: [
{ name: "Autre action", command: 'autre' },
{ name: 'Initiative +1', command: 'inc', value: 0.01 },
{ name: 'Initiative -1', command: 'dec', value: -0.01 }]
};
const controlIconCombat = html.find('.control-icon[data-action=combat]');
// initiative
await RdDTokenHud._configureSubMenu(controlIconCombat, 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-init.html', hudData,
await RdDTokenHud._configureSubMenu(controlIconCombat,
'systems/foundryvtt-reve-de-dragon/templates/hud-actor-init.html',
hudData,
(event) => {
let initCommand = event.currentTarget.attributes['data-command'].value;
let combatantId = event.currentTarget.attributes['data-combatant-id'].value;
if (!initCommand) {
let armeIndex = event.currentTarget.attributes['data-arme-id'].value;
let arme = armesList[armeIndex];
RdDCombatManager.rollInitiativeCompetence(combatantId, arme);
} else if (initCommand == 'inc') {
RdDCombatManager.incDecInit(combatantId, 0.01);
} else if (initCommand == 'dec') {
RdDCombatManager.incDecInit(combatantId, -0.01);
}
let initCommand = event.currentTarget.attributes['data-command']?.value;
let combatantId = event.currentTarget.attributes['data-combatant-id']?.value;
if (initCommand) {
RdDTokenHud._initiativeCommand(initCommand, combatantId);
} else {
let index = event.currentTarget.attributes['data-action-index'].value;
let action = actionsCombat[index];
RdDCombatManager.rollInitiativeAction(combatantId, action);
}
});
const controlIconTarget = html.find('.control-icon[data-action=target]');
// combat
await RdDTokenHud._configureSubMenu(controlIconTarget, 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-attaque.html', hudData,
(event) => {
let armeIndex = event.currentTarget.attributes['data-arme-id'].value;
actor.rollArme(armesList[armeIndex]);
const actionIndex = event.currentTarget.attributes['data-action-index']?.value;
const action = actionsCombat[actionIndex];
if (action.action == 'conjurer') {
actor.conjurerPossession(actor.getPossession(action.data.possessionid));
}
else {
actor.rollArme(action);
}
});
}
static _initiativeCommand(initCommand, combatantId) {
switch (initCommand) {
case 'inc': return RdDCombatManager.incDecInit(combatantId, 0.01);
case 'dec': return RdDCombatManager.incDecInit(combatantId, -0.01);
case 'autre': return RdDCombatManager.rollInitiativeAction(combatantId,
{ name: "Autre action", action: 'autre', data: { initOnly: true, competence: "Autre action" } });
}
}
/* -------------------------------------------- */
static async addTokenHudExtensions(app, html, tokenId) {
const controlIconCombat = html.find('.control-icon[data-action=combat]');

View File

@@ -11,6 +11,7 @@ import { RdDDice } from "./rdd-dice.js";
import { RdDItem } from "./item.js";
import { Monnaie } from "./item-monnaie.js";
import { RdDPossession } from "./rdd-possession.js";
import { RdDNameGen } from "./rdd-namegen.js";
/* -------------------------------------------- */
// This table starts at 0 -> niveau -10
@@ -694,7 +695,7 @@ export class RdDUtility {
actor.tmrApp.lancerSortEnReserve(coord, sortId);
});
// gestion bouton tchat Acheter
// gestion bouton tchat Possession
html.on("click", '.defense-possession', event => {
let attackerId = event.currentTarget.attributes['data-attackerId'].value
let defenderId = event.currentTarget.attributes['data-defenderId'].value
@@ -704,6 +705,7 @@ export class RdDUtility {
// gestion bouton tchat Acheter
html.on("click", '.button-acheter', event => DialogItemAchat.onButtonAcheter(event));
html.on("click", '.button-creer-acteur', event => RdDNameGen.onCreerActeur(event));
// Gestion du bouton payer
html.on("click", '.payer-button', event => {

File diff suppressed because one or more lines are too long

View File

@@ -29,7 +29,7 @@
"url": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/",
"license": "LICENSE.txt",
"flags": {},
"version": "1.5.79",
"version": "1.5.84",
"minimumCoreVersion": "0.8.0",
"compatibleCoreVersion": "9",
"scripts": [],
@@ -500,7 +500,7 @@
"dependencies": [],
"socket": true,
"manifest": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/v1.5/system.json",
"download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-1.5.79.zip",
"download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-1.5.84.zip",
"protected": false,
"gridDistance": 1,
"gridUnits": "m",

View File

@@ -28,7 +28,7 @@
{{!-- Carac Tab --}}
<div class="tab items" data-group="primary" data-tab="carac">
<div class="grid grid-2col">
<div class="flex-group-left flexcol">
<ol class="carac-list alterne-list">
@@ -65,6 +65,7 @@
{{#select data.definition.typeentite}}
<option value="incarne">Incarnée</option>
<option value="nonincarne">Non Incarnée</option>
<option value="blurette">Blurete</option>
{{/select}}
</select>
</li>
@@ -89,9 +90,7 @@
{{!-- Compétences Tab --}}
<div class="tab competences" data-group="primary" data-tab="competences">
<div class="flexcol">
<div class="flex-group-left flexcol competence-column">
<ol class="item-list alterne-list">
{{#each competences as |comp key|}}
@@ -111,25 +110,24 @@
</li>
{{/each}}
</ol>
<div class="flex-group-left flexcol competence-column">
<ol class="item-list alterne-list">
{{#each possessions as |possession key|}}
<li class="item flexrow list-item" data-item-id="{{possession._id}}">
<img class="sheet-competence-img" src="{{possession.img}}" />
<span class="competence-label">{{possession.name}}</span>
<div class="item-controls">
<a class="item-control item-edit" title="Edit Item"><i class="fas fa-edit"></i></a>
<a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
</div>
</li>
{{/each}}
</ol>
</div>
<div class="flex-group-left flexcol competence-column">
<ol class="item-list alterne-list">
{{#each possessions as |possession key|}}
<li class="item flexrow list-item" data-item-id="{{possession._id}}">
<img class="sheet-competence-img" src="{{possession.img}}" />
<span class="competence-label">{{possession.name}}</span>
<div class="item-controls">
<a class="item-control item-edit" title="Edit Item"><i class="fas fa-edit"></i></a>
<a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
</div>
</li>
{{/each}}
</ol>
</div>
</div>
</div>
{{!-- Biography Tab --}}
<div class="tab description" data-group="primary" data-tab="description">
<div class="form-group editor">
@@ -137,8 +135,6 @@
</div>
{{>"systems/foundryvtt-reve-de-dragon/templates/actor-sheet-editor-notes-mj.html"}}
</div>
</div>
</section>
</form>

View File

@@ -321,6 +321,7 @@
{{!-- Liste de blessures --}}
{{> "systems/foundryvtt-reve-de-dragon/templates/actor-liste-blessures-partial.html" this}}
{{#if maladiesPoisons.length}}
{{!-- Maladies & Poison --}}
<h3 class="blessures-title">Maladies & Poisons:</h3>
<ul class="item-list alterne-list">
@@ -354,28 +355,30 @@
</li>
{{/each}}
</ul>
{{/if}}
{{!-- Possession --}}
<h3 class="blessures-title">Possession:</h3>
<ul class="item-list alterne-list">
<li class="competence-header flexrow">
<span class="competence-title flex-grow competence-label">Nom</span>
<span class="competence-title competence-label">Type</span>
</li>
{{#if possessions.length}}
{{!-- Possession --}}
<h3 class="blessures-title">Possession:</h3>
<ul class="item-list alterne-list">
<li class="competence-header flexrow">
<span class="competence-title flex-grow competence-label">Nom</span>
<span class="competence-title competence-label">Type</span>
</li>
{{#each possessions as |possession key|}}
<li class="item flexrow list-item" data-item-id="{{possession._id}}">
<span class="competence-label">
<a class="sheet-possession-attack">{{possession.name}} (Conjurer)</a>
</span>
<span class="competence-label">{{possession.data.type}}</span>
<div class="item-controls">
<a class="item-control item-edit" title="Modifier"><i class="fas fa-edit"></i></a>
<a class="item-control item-delete" title="Supprimer"><i class="fas fa-trash"></i></a>
</div>
</li>
{{/each}}
</ul>
<li class="item flexrow list-item" data-item-id="{{possession._id}}">
<span class="competence-label">
<a class="sheet-possession-attack">{{possession.name}} (Conjurer)</a>
</span>
<span class="competence-label">{{possession.data.type}}</span>
<div class="item-controls">
<a class="item-control item-edit" title="Modifier"><i class="fas fa-edit"></i></a>
<a class="item-control item-delete" title="Supprimer"><i class="fas fa-trash"></i></a>
</div>
</li>
{{/each}}
</ul>
{{/if}}
</div>
{{!-- Connaissances Tab --}}

View File

@@ -0,0 +1,16 @@
<h4>Proposition de nom: {{nom}}</h4>
<span class="chat-card-button-area">
<a class="button-creer-acteur chat-card-button"
data-nom='{{nom}}'
data-type='personnage'
>
Créer un Personnage</a>
</span>
<span class="chat-card-button-area">
<a class="button-creer-acteur chat-card-button"
data-nom='{{nom}}'
data-type='creature'>
Créer une créature</a>
</span>

View File

@@ -1,31 +1,38 @@
<img class="chat-icon" src="{{competence.img}}" />
<h4>
{{#if (eq mode "possession")}}
{{alias}} tente de posséder {{possede}}
{{attacker.name}} tente de {{#if isECNIDefender}}conjurer la possession de{{else}}posséder{{/if}} {{defender.name}}
{{else}}
{{alias}} tente de conjurer la possession de {{possesseur}}
{{defender.name}} tente de {{#if isECNIDefender}}résister à{{else}}conjurer la possession de{{/if}} {{attacker.name}}
{{/if}}
</h4>
{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.html"}}
<hr>
<div>
<span class='chat-card-button-area'>
<br>
{{#if (eq mode "possession")}}
{{#if possession.isSuccess}}
<a class='defense-possession chat-card-button' data-attackerId='{{attackerId}}'
data-defenderId='{{defenderId}}' data-possessionId='{{possession.data.possessionid}}'>Résister à la possession</a>
</a>
<a class='defense-possession chat-card-button'
data-attackerId='{{attacker.id}}'
data-defenderId='{{defender.id}}'
data-possessionId='{{possession.data.possessionid}}'>
{{#if isECNIDefender}}
Résister à la conjuration
{{else}}
Résister à la possession
{{/if}}
</a>
{{else}}
La Tentative de Possession a échouée !
La Tentative de {{#if isECNIDefender}}conjuration{{else}}possession{{/if}} a échoué !
{{/if}}
{{else}}
{{#if rolled.isSuccess}}
La Tentative de Possession a été conjurée ! {{alias}} résiste à la tentative de possession.
{{else}}
La Tentative de Possession n'a pas pu être conjurée !
La tentative de {{#if isECNIDefender}}conjuration a été repoussée{{else}}possession a été conjurée{{/if}}!
{{defender.name}} a résisté.
{{else}}
La tentative de {{#if isECNIDefender}}conjuration a réussi{{else}}possession n'a pas pu être conjurée{{/if}}!
{{/if}}
{{/if}}
<br>Points de Possession: {{possession.ptsPossession}}

View File

@@ -1,5 +1,9 @@
<form class="skill-roll-dialog">
<h2>Conjuration d'une Possession {{possession.name}}!</h2>
<h2>
{{defender.name}} tente de
{{#if isECNIDefender}}maintenir{{else}}résister à{{/if}}
la possession de {{attacker.name}}
</h2>
<div class="grid grid-2col">
<div class="flex-group-left">
<img class="chat-icon" src="{{competence.img}}" alt="{{competence.name}}"/>

View File

@@ -1,10 +1,13 @@
<div class="control-icon rdd-combat ">
<img class="rdd-hud-togglebutton" src="systems/foundryvtt-reve-de-dragon/icons/heures/hd06.svg" width="36" height="36" title="Attaque"/>
<div class="rdd-hud-list tokenhudext left">
{{#each armes as |arme key|}}
{{#unless arme.data.initOnly}}
<div class="control-icon tokenhudicon rdd-hud-menu rdd-attaque" data-combatant-id="{{../combatant.id}}" data-arme-id="{{arme.index}}" title="{{arme.name}}">
<label>C:{{arme.name}} {{arme.data.mainInfo}}</label>
{{#each actions as |action key|}}
{{#unless action.data.initOnly}}
<div class="control-icon tokenhudicon rdd-hud-menu rdd-attaque"
data-combatant-id="{{../combatant.id}}"
data-action-index="{{action.index}}"
title="{{action.name}}">
<label>{{action.name}} {{action.data.mainInfo}}</label>
</div>
{{/unless}}
{{/each}}

View File

@@ -1,14 +1,22 @@
<div class="control-icon rdd-initiative ">
<img class="rdd-hud-togglebutton" src="icons/svg/sword.svg" width="36" height="36" title="Initiative" />
<div class="rdd-hud-list tokenhudext right">
{{#each armes as |arme key|}}
<div class="control-icon tokenhudicon rdd-hud-menu" data-command="{{arme.command}}" data-combatant-id="{{../combatant.id}}" data-arme-id="{{arme.index}}" title="{{arme.name}}">
<label>I:{{arme.name}} {{arme.data.mainInfo}}</label>
{{#each actions as |action key|}}
{{log 'action-hud-init' action}}
<div class="control-icon tokenhudicon rdd-hud-menu"
data-combatant-id="{{../combatant.id}}"
data-action-index="{{action.index}}"
title="{{action.name}}">
<label>init: {{action.name}} {{action.data.mainInfo}}</label>
</div>
{{/each}}
{{#each commandes as |commande key|}}
<div class="control-icon tokenhudicon rdd-hud-menu" data-command="{{commande.command}}" data-combatant-id="{{../combatant.id}}" data-arme-id="{{commande.index}}" title="{{commande.name}}">
<label>I:{{commande.name}}</label>
<div class="control-icon tokenhudicon rdd-hud-menu"
data-command="{{commande.command}}"
data-combatant-id="{{../combatant.id}}"
data-action-index="{{commande.index}}"
title="{{commande.name}}">
<label>{{commande.name}}</label>
</div>
{{/each}}
</div>