Compare commits

...

9 Commits

Author SHA1 Message Date
uberwald 54df875451 Merge pull request 'v10.7.20 - la cuirasse de Sémolosse' (#662) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: #662
2023-07-12 08:09:06 +02:00
Vincent Vandemeulebrouck 253a1bd433 v10.7.20 - la cuirasse de Sémolosse
- correction de méthodes qui filtrent les items
  - recherche de cases TMR
  - recherche de tâches de lecture
  - recherche d'armure (pour le malus armure)
  - recherche de potions
2023-07-12 00:46:46 +02:00
Vincent Vandemeulebrouck e58d88fab6 Fix: filterItem ne marchait plus sans type 2023-07-12 00:39:21 +02:00
uberwald 41d2404de2 Merge pull request 'v10.7.20 - la poigne de Sémolosse' (#655) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: #655
2023-06-19 15:36:32 +02:00
Vincent Vandemeulebrouck 631ee0b801 v10.7.20 - La poigne de Sémolosse 2023-06-15 02:02:00 +02:00
Vincent Vandemeulebrouck ed9c574cd2 Fin d'empoignade
En cours de round en atteignant 2 points d'empoignade, on peut
uniquement entraîner au sol.

En fin de round, si la victime est immobilisée, on peut projeter, ou
faire perdre de l'endurance
2023-06-15 01:59:17 +02:00
Vincent Vandemeulebrouck bb624e8e96 Restreindre les actions d'empoignade
Seul le propriétaire du défenseur peut effecuer les contres
d'empoignade ou tenter de se libérer.

Seul le propriétaire de l'empoigneur peut tenter d'empêcher
la libération du défenseur, de projeter au sol, ou de faire perdre
de l'endurance.
2023-06-15 01:03:33 +02:00
Vincent Vandemeulebrouck 40f2ac8714 Correction malus de taille empoignade 2023-06-15 00:30:11 +02:00
Vincent Vandemeulebrouck 804fa3b784 Fix empoignade
- les items d'empoignade sont ajoutés par le MJ
- les caractéristiques du défenseur sont utilisées pour la défense
- la difficulté d'attaque est imposée au défenseur
- les particulières sont en finesse (p133)
2023-06-15 00:30:11 +02:00
17 changed files with 368 additions and 219 deletions

View File

@ -1,6 +1,23 @@
# v10.7 - L'os de Semolosse
# v10.7 - L'os de Sémolosse
## v10.7.19 - les fantômes de Semolosse
## v10.7.20 - la poigne de Sémolosse
- correction de méthodes qui filtrent les items
- recherche de cases TMR
- recherche de tâches de lecture
- recherche d'armure (pour le malus armure)
- recherche de potions
## v10.7.20 - la poigne de Sémolosse
- correction de l'empoignade
- les items d'empoignade sont ajoutés par le MJ quand nécessaire
- seul le joueur propriétaire du personnage peut effectuer ses choix et actions d'empoignade
- les caractéristiques du défenseur sont utilisées pour la défense
- la difficulté d'attaque est imposée au défenseur
- les attaques particulières sont en finesse (p133)
- on peut entraîner au sol dès 2 points d'empoignade
- les actions liée à l'immobilisation sont proposées en fin de round
## v10.7.19 - les fantômes de Sémolosse
- les créatures ont maintenant le droit d'avoir des compétences de tir, lancer, mêlée, armes naturelles, parade.
- les créatures armées utilisent la bonne phase d'initiative
- correction des possessions
@ -9,38 +26,38 @@
- le rêve actuel des personnages est bien utilisé
- correction des achats par le MJ sans acteur sélectionné
## v10.7.18 - le repos de Semolosse
## v10.7.18 - le repos de Sémolosse
- correction des dates de blessures qui ne marchaient plus
## v10.7.17 - le doigt du destin de Semolosse
## v10.7.17 - le doigt du destin de Sémolosse
- correction de la validation d'encaissement par le MJ
## v10.7.16 - la morsure de Semolosse
## v10.7.16 - la morsure de Sémolosse
- correction de l'affichage des objets suite à confusion
- correction de liens dans la liste des équipements
## v10.7.14 - l'expérience de Semolosse
## v10.7.14 - l'expérience de Sémolosse
- Affichage des personnages accordés sur les fiches des entités
- Refonte du journal d'expérience
- disponible pour les personnages des joueurs
- explication "comptable" des changements (dépense ou ajout, changements de niveaux, ...)
- tri alphabétique des différentes listes (sorts, recettes, oeuvres, ...)
## v10.7.13 - l'armure de Semolosse
## v10.7.13 - l'armure de Sémolosse
- Fix: en cas d'armure variable, la détérioration diminue le dé d'armure
## v10.7.12
- Fix: si le MJ gère les changements de jours, l'option "sieste" de la fenêtre de repos est prise par défaut si chateau dormant n'est pas passé
## v10.7.11 - Le Pugilat de Semolosse
## v10.7.11 - Le Pugilat de Sémolosse
- Fix sur la projection au sol.
## v10.7.10 - Le Pugilat de Semolosse
## v10.7.10 - Le Pugilat de Sémolosse
- Gestion de l'empoignade
- Corrections sur l'initiative
- Correction sur l'equipement des vêtements et bijoux
## v10.7.9 - Le Pugilat de Semolosse
## v10.7.9 - Le Pugilat de Sémolosse
- Gestion assistée de l'empoignade
1. On selectionne sa cible (ie le token qui va être empoigné)
@ -106,14 +123,14 @@
- Horloge
- A l'heure de Couronne pile, les aiguilles des heures et des minutes pointent sur couronne (comme une montre) au lieu d'avoir l'aiguille des heures 15° à gauche
## v10.7.2 - les maux de dents de Semolosse
## v10.7.2 - les maux de dents de Sémolosse
- correction des récupérations de blessures
- la fin de château dormant se passe normalement
## v10.7.1 - L'os de Semolosse
## v10.7.1 - L'os de Sémolosse
- Fix rapide sur les jets de carac qui n'étaient plus possibles
## v10.7.0 - L'os de Semolosse
## v10.7.0 - L'os de Sémolosse
- gestion des blessures en items
- soins du token ciblé par menu contextuel (comme le combat)
- automatisation des soins et de l'affichage de l'avancement des soins

View File

@ -273,24 +273,24 @@ export class RdDActor extends RdDBaseActor {
getDraconicOuPossession() {
const possession = this.items.filter(it => it.type == TYPES.competencecreature && it.system.categorie == 'possession')
.sort(Misc.descending(it => it.system.niveau))
.find(it=>true);
.find(it => true);
if (possession) {
return possession.clone();
}
const draconics = [...this.getDraconicList().filter(it => it.system.niveau >= 0).map(it =>it.clone()),
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 draconics[0];
}
getPossession(possessionId) {
return this.items.find(it => it.type == 'possession' && it.system.possessionid == possessionId);
return this.items.find(it => it.type == TYPES.possession && it.system.possessionid == possessionId);
}
getPossessions() {
return this.items.filter(it => it.type == 'possession');
return this.items.filter(it => it.type == TYPES.possession);
}
getEmpoignades() {
return this.items.filter(it => it.type == 'empoignade');
return this.items.filter(it => it.type == TYPES.empoignade);
}
getDemiReve() {
return this.system.reve.tmrpos.coord;
@ -298,7 +298,7 @@ export class RdDActor extends RdDBaseActor {
/* -------------------------------------------- */
async verifierPotionsEnchantees() {
let potionsEnchantees = this.filterItems(it => it.type == 'potion' && it.system.categorie.toLowerCase().includes('enchant'));
let potionsEnchantees = this.filterItems(it => it.system.categorie.toLowerCase().includes('enchant'), 'potion');
for (let potion of potionsEnchantees) {
if (!potion.system.prpermanent) {
console.log(potion);
@ -961,7 +961,7 @@ export class RdDActor extends RdDBaseActor {
/* -------------------------------------------- */
async updateCompetence(idOrName, compValue) {
const competence = this.getCompetence(idOrName);
const competence = this.getCompetence(idOrName);
if (competence) {
const toNiveau = compValue ?? RdDItemCompetence.getNiveauBase(competence.system.categorie, competence.getCategories());
this.notifyCompetencesTronc(competence, toNiveau);
@ -1124,7 +1124,7 @@ export class RdDActor extends RdDBaseActor {
/* -------------------------------------------- */
async computeMalusArmure() {
if (this.isPersonnage()) {
const malusArmure = this.filterItems(it => it.type == 'armure' && it.system.equipe)
const malusArmure = this.filterItems(it => it.system.equipe, 'armure')
.map(it => it.system.malus ?? 0)
.reduce(Misc.sum(), 0);
// Mise à jour éventuelle du malus armure
@ -1297,8 +1297,7 @@ export class RdDActor extends RdDBaseActor {
/* -------------------------------------------- */
buildTMRInnaccessible() {
const tmrInnaccessibles = this.filterItems(it => Draconique.isCaseTMR(it) &&
EffetsDraconiques.isInnaccessible(it));
const tmrInnaccessibles = this.filterItems(it => Draconique.isCaseTMR(it) && EffetsDraconiques.isInnaccessible(it));
return tmrInnaccessibles.map(it => it.system.coord);
}
@ -1362,21 +1361,46 @@ export class RdDActor extends RdDBaseActor {
/* -------------------------------------------- */
async finDeRound(options = { terminer: false }) {
await this.$finDeRoundSuppressionEffetsTermines(options);
await this.$finDeRoundBlessuresGraves();
await this.$finDeRoundSupprimerObsoletes();
await this.$finDeRoundEmpoignade();
}
async $finDeRoundSuppressionEffetsTermines(options) {
for (let effect of this.getEffects()) {
if (effect.duration.type !== 'none' && (effect.duration.remaining <= 0 || options.terminer)) {
await effect.delete();
ChatMessage.create({ content: `${this.name} n'est plus ${Misc.lowerFirst(game.i18n.localize(effect.system.label))} !` });
}
}
}
async $finDeRoundBlessuresGraves() {
if (this.isPersonnage() || this.isCreature()) {
const nbGraves = this.filterItems(it => it.isGrave(), 'blessure').length
const nbGraves = this.filterItems(it => it.isGrave(), 'blessure').length;
if (nbGraves > 0) {
// Gestion blessure graves : -1 pt endurance par blessure grave
await this.santeIncDec("endurance", - nbGraves);
await this.santeIncDec("endurance", -nbGraves);
}
}
}
async $finDeRoundSupprimerObsoletes() {
const obsoletes = []
.concat(this.itemTypes[TYPES.empoignade].filter(it => it.system.pointsemp <= 0))
.concat(this.itemTypes[TYPES.possession].filter(it => it.system.compteur < -2 || it.system.compteur > 2))
.map(it => it.id);
await this.deleteEmbeddedDocuments('Item', obsoletes);
}
async $finDeRoundEmpoignade(){
const immobilisations = this.itemTypes[TYPES.empoignade].filter(it => it.system.pointsemp >= 2 && it.system.empoigneurid == this.id);
immobilisations.forEach(emp => RdDEmpoignade.onImmobilisation(this,
game.actors.get(emp.system.empoigneid),
emp
))
}
/* -------------------------------------------- */
async setSonne(sonne = true) {
if (this.isEntite()) {
@ -2338,8 +2362,7 @@ export class RdDActor extends RdDBaseActor {
/* -------------------------------------------- */
async creerTacheDepuisLivre(item, options = { renderSheet: true }) {
const nomTache = "Lire " + item.name;
const filterTacheLecture = it => it.type == 'tache' && it.name == nomTache;
let tachesExistantes = this.filterItems(filterTacheLecture);
let tachesExistantes = findTache(nomTache);
if (tachesExistantes.length == 0) {
const tache = {
name: nomTache, type: 'tache',
@ -2355,13 +2378,17 @@ export class RdDActor extends RdDBaseActor {
}
}
await this.createEmbeddedDocuments('Item', [tache], options);
tachesExistantes = this.filterItems(filterTacheLecture);
tachesExistantes = findTache(nomTache)
}
return tachesExistantes.length > 0 ? tachesExistantes[0] : undefined;
function findTache(name) {
return this.filterItems(it => it.name == name, 'tache');
}
}
blessuresASoigner() {
// TODO or not TODO: filtrer les blessures poour lesquels on ne peut plus faire de premiers soins?
// TODO or not TODO: filtrer les blessures pour lesquelles on ne peut plus faire de premiers soins?
return this.filterItems(it => it.system.gravite > 0 && it.system.gravite <= 6 && !(it.system.premierssoins.done && it.system.soinscomplets.done), 'blessure')
}

View File

@ -119,7 +119,7 @@ export class RdDBaseActor extends Actor {
}
listItems(type = undefined) { return (type ? this.itemTypes[type] : this.items); }
filterItems(filter, type = undefined) { return type ? this.itemTypes[type]?.filter(filter) ?? [] : []; }
filterItems(filter, type = undefined) { return (type ? this.itemTypes[type] : this.items)?.filter(filter); }
findItemLike(idOrName, type) {
return this.getItem(idOrName, type)
?? Misc.findFirstLike(idOrName, this.listItems(type), { description: Misc.typeName('Item', type) });
@ -144,6 +144,18 @@ export class RdDBaseActor extends Actor {
.forEach(async it => await it.onFinPeriodeTemporel(oldTimestamp, newTimestamp))
}
async creerObjetParMJ(object){
if (!Misc.isUniqueConnectedGM()) {
RdDBaseActor.remoteActorCall({
actorId: this.id,
method: 'creerObjetParMJ',
args: [object]
});
return;
}
await this.createEmbeddedDocuments('Item', [object])
}
/* -------------------------------------------- */
getFortune() {
return Monnaie.getFortune(this.itemTypes['monnaie']);

View File

@ -78,11 +78,7 @@ export class ChatUtility {
/* -------------------------------------------- */
static async createChatWithRollMode(name, chatOptions) {
return await ChatUtility.createChatMessage(name, game.settings.get("core", "rollMode"), chatOptions);
}
/* -------------------------------------------- */
static async createChatMessage(name, rollMode, chatOptions) {
let rollMode = game.settings.get("core", "rollMode")
switch (rollMode) {
case "blindroll": // GM only
if (!game.user.isGM) {

View File

@ -4,6 +4,8 @@ import { RdDRoll } from "./rdd-roll.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { ChatUtility } from "./chat-utility.js";
import { STATUSES } from "./settings/status-effects.js";
import { ReglesOptionelles } from "./settings/regles-optionelles.js";
import { TYPES } from "./item.js";
/* -------------------------------------------- */
@ -14,6 +16,47 @@ export class RdDEmpoignade {
static init() {
}
/* -------------------------------------------- */
static registerChatCallbacks(html) {
html.on("click", '.defense-empoignade-cac', event => {
const chatMessage = ChatUtility.getChatMessage(event);
const rollData = RdDEmpoignade.$readRollEmpoignade(chatMessage);
let defenseMode = event.currentTarget.attributes['data-defense-mode'].value
RdDEmpoignade.onDefenseEmpoignade(rollData, defenseMode, "Corps à corps", "melee")
});
html.on("click", '.defense-empoignade-esquive', event => {
const chatMessage = ChatUtility.getChatMessage(event);
const rollData = RdDEmpoignade.$readRollEmpoignade(chatMessage);
let defenseMode = event.currentTarget.attributes['data-defense-mode'].value
RdDEmpoignade.onDefenseEmpoignade(rollData, defenseMode, "Esquive", "derobee")
});
html.on("click", '.empoignade-poursuivre', event => {
let attackerId = event.currentTarget.attributes['data-attackerId'].value
let defenderId = event.currentTarget.attributes['data-defenderId'].value
RdDEmpoignade.onAttaqueEmpoignadeValidee(game.actors.get(attackerId), game.actors.get(defenderId))
});
html.on("click", '.empoignade-entrainer-sol', event => {
const chatMessage = ChatUtility.getChatMessage(event);
const rollData = RdDEmpoignade.$readRollEmpoignade(chatMessage);
RdDEmpoignade.entrainerAuSol(rollData)
ChatUtility.removeChatMessageId(chatMessage.id)
});
html.on("click", '.empoignade-projeter-sol', event => {
const chatMessage = ChatUtility.getChatMessage(event);
const rollData = RdDEmpoignade.$readRollEmpoignade(chatMessage);
RdDEmpoignade.projeterAuSol(rollData)
ChatUtility.removeChatMessageId(chatMessage.id)
});
html.on("change", '.empoignade-perte-endurance', event => {
const chatMessage = ChatUtility.getChatMessage(event);
const rollData = RdDEmpoignade.$readRollEmpoignade(chatMessage);
if (event.currentTarget.value && event.currentTarget.value != "none") {
RdDEmpoignade.perteEndurance(rollData, event.currentTarget.value)
ChatUtility.removeChatMessageId(chatMessage.id)
}
});
}
/* -------------------------------------------- */
static checkEmpoignadeEnCours(actor) {
// TODO: autoriser la perception? la comédie/séduction?
@ -24,74 +67,92 @@ export class RdDEmpoignade {
return false;
}
/* -------------------------------------------- */
static $storeRollEmpoignade(msg, rollData) {
RdDEmpoignade.$reduceActorToIds(rollData);
ChatUtility.setMessageData(msg, "empoignade-roll-data", rollData);
}
static $reduceActorToIds(rollData) {
rollData.attacker = { id: rollData.attacker.id };
rollData.defender = { id: rollData.defender.id };
}
/* -------------------------------------------- */
static $readRollEmpoignade(msg) {
const rollData = ChatUtility.getMessageData(msg, 'empoignade-roll-data');
RdDEmpoignade.$replaceIdsWithActors(rollData);
return rollData
}
static $replaceIdsWithActors(rollData) {
rollData.attacker = game.actors.get(rollData.attacker.id);
rollData.defender = game.actors.get(rollData.defender.id);
}
/* -------------------------------------------- */
static isEmpoignadeEnCours(actor) {
return actor.itemTypes['empoignade'].find(it => it.system.pointsemp > 0)
return actor.itemTypes[TYPES.empoignade].find(it => it.system.pointsemp > 0)
}
/* -------------------------------------------- */
static getEmpoignadeById(actor, id) {
let emp = actor.itemTypes['empoignade'].find(it => it.system.empoignadeid == id)
let emp = actor.itemTypes[TYPES.empoignade].find(it => it.system.empoignadeid == id)
return emp && duplicate(emp) || undefined;
}
/* -------------------------------------------- */
static getEmpoignade(attacker, defender) {
let emp = attacker.itemTypes['empoignade'].find(it => it.system.empoigneurid == attacker.id && it.system.empoigneid == defender.id)
if (!emp) {
emp = attacker.itemTypes['empoignade'].find(it => it.system.empoigneurid == defender.id && it.system.empoigneid == attacker.id)
}
let emp = attacker.itemTypes[TYPES.empoignade].find(it =>
(it.system.empoigneurid == attacker.id && it.system.empoigneid == defender.id) ||
(it.system.empoigneurid == defender.id && it.system.empoigneid == attacker.id)
)
if (emp) {
return duplicate(emp);
}
return undefined;
}
/* -------------------------------------------- */
static getMalusTaille(emp, attacker, defender) {
// Si pas empoigné, alors 0
if (emp.system.pointsemp == 0) {
return 0
}
// Malus de -1 si différence de taille de 2 ou plus (p 135)
if (attacker.system.carac.taille.value < defender.system.carac.taille.value - 1) {
return attacker.system.carac.taille.value - (defender.system.carac.taille.value - 1)
// p135: Malus de -1 par point de taille de différence de taille au delà de 1 (donc -2 pour une différence de 3, ...)
const diffTaille = attacker.system.carac.taille.value - defender.system.carac.taille.value;
const diffTailleAbs = Math.abs(diffTaille)
const signDiff = diffTaille > 0 ? 1 : -1
if (diffTailleAbs > 2) {
return signDiff * (diffTailleAbs - 1)
}
return 0
}
/* -------------------------------------------- */
static async onAttaqueEmpoignadeValidee(attacker, defender) {
let empoignade = RdDEmpoignade.getEmpoignade(attacker, defender)
const isNouvelle = empoignade == undefined;
empoignade = empoignade ?? (await RdDEmpoignade.createEmpoignade(attacker, defender))
static isActionAutorisee(mode, attacker, defender) {
const acting = RdDEmpoignade.isActionDefenseur(mode) ? defender : attacker;
if (acting.getUserLevel(game.user) < CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER) {
ui.notifications.warn(`Vous n'êtes pas autorisé à choisir l'action de ${acting.name}`)
return false;
}
return true
}
let mode = (empoignade && empoignade.system.empoigneurid == attacker.id) ? "empoigner" : "liberer"
let rollData = {
mode: mode,
isEmpoignade: true,
competence: attacker.getCompetence("Corps à corps").clone(),
selectedCarac: attacker.system.carac.melee,
empoignade: empoignade,
attackerId: attacker.id,
attackerName: attacker.name,
defenderName: defender.name,
defenderId: defender.id,
malusTaille: RdDEmpoignade.getMalusTaille(empoignade, attacker, defender)
}
if (attacker.isCreatureEntite()) {
RdDItemCompetenceCreature.setRollDataCreature(rollData)
}
if (empoignade.system.pointsemp >= 2) {
let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-actions.html');
ChatUtility.setMessageData(msg, "empoignade-roll-data", rollData)
} else {
await RdDEmpoignade.$rollAttaqueEmpoignade(attacker, rollData, isNouvelle);
static isActionDefenseur(mode) {
switch (mode) {
case "liberer":
case "contrer-empoigner":
return true;
}
return false;
}
/* -------------------------------------------- */
static async onAttaqueEmpoignade(attacker, defender) {
if (!RdDEmpoignade.isActionAutorisee("empoigner", attacker, defender)) {
return
}
let empoignade = RdDEmpoignade.getEmpoignade(attacker, defender)
const isNouvelle = empoignade == undefined;
empoignade = empoignade ?? (await RdDEmpoignade.createEmpoignade(attacker, defender))
@ -105,6 +166,38 @@ export class RdDEmpoignade {
}
}
/* -------------------------------------------- */
static async onAttaqueEmpoignadeValidee(attacker, defender) {
let empoignade = RdDEmpoignade.getEmpoignade(attacker, defender)
const isNouvelle = empoignade == undefined;
empoignade = empoignade ?? (await RdDEmpoignade.createEmpoignade(attacker, defender))
let mode = (empoignade && empoignade.system.empoigneurid == attacker.id) ? "empoigner" : "liberer"
if (!RdDEmpoignade.isActionAutorisee(mode, attacker, defender)) {
return
}
let rollData = {
mode, empoignade, attacker, defender,
isEmpoignade: true,
competence: attacker.getCompetence("Corps à corps").clone(),
selectedCarac: attacker.system.carac.melee,
malusTaille: RdDEmpoignade.getMalusTaille(empoignade, attacker, defender)
}
if (attacker.isCreatureEntite()) {
RdDItemCompetenceCreature.setRollDataCreature(rollData)
}
if (empoignade.system.pointsemp >= 2) {
if (!empoignade.system.ausol) {
let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-entrainer.html');
RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
}
} else {
await RdDEmpoignade.$rollAttaqueEmpoignade(attacker, rollData, isNouvelle);
}
}
/* -------------------------------------------- */
static async onAttaqueEmpoignadeFromItem(empoignade) {
let attacker = game.actors.get(empoignade.system.empoigneurid)
@ -112,6 +205,20 @@ export class RdDEmpoignade {
await this.onAttaqueEmpoignadeValidee(attacker, defender)
}
static async onImmobilisation(attacker, defender, empoignade) {
const rollData = {
mode: "immobilise",
empoignade, attacker, defender,
isEmpoignade: true,
competence: attacker.getCompetence("Corps à corps").clone()
}
const msg = await ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(attacker.name),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-empoignade-immobilise.html`, rollData)
})
RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
}
/* -------------------------------------------- */
static async $rollAttaqueEmpoignade(attacker, rollData, isNouvelle = false) {
const dialog = await RdDRoll.create(attacker, rollData,
@ -119,35 +226,40 @@ export class RdDEmpoignade {
{
name: 'jet-empoignade',
label: 'Empoigner',
callbacks: [
{ condition: r => (r.rolled.isSuccess), action: async (r) => await RdDEmpoignade.$onRollEmpoignade(r, true, isNouvelle) },
{ condition: r => (r.rolled.isEchec), action: async (r) => await RdDEmpoignade.$onRollEmpoignade(r, false, isNouvelle) },
]
callbacks: [{ action: async (r) => await RdDEmpoignade.$onRollEmpoignade(r, isNouvelle) },]
});
dialog.render(true);
}
/* -------------------------------------------- */
static async $onRollEmpoignade(rollData, isSuccess, isNouvelle = false) {
let attacker = game.actors.get(rollData.attackerId)
let defender = game.actors.get(rollData.defenderId)
static async $onRollEmpoignade(rollData, isNouvelle = false) {
let attacker = game.actors.get(rollData.attacker.id)
let defender = game.actors.get(rollData.defender.id)
let empoignade = rollData.empoignade
empoignade.isSuccess = isSuccess;
if (isSuccess && isNouvelle) {
if (rollData.rolled.isSuccess && isNouvelle) {
const objectEmpoignade = rollData.empoignade.toObject();
// Creer l'empoignade sur attaquant/defenseur
await attacker.createEmbeddedDocuments('Item', [empoignade.toObject()])
await defender.createEmbeddedDocuments('Item', [empoignade.toObject()])
attacker.creerObjetParMJ(objectEmpoignade);
defender.creerObjetParMJ(objectEmpoignade);
}
rollData.empoignade.isSuccess = rollData.rolled.isSuccess;
if (rollData.rolled.isPart) {
rollData.particuliere = "finesse";
}
let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-resultat.html');
ChatUtility.setMessageData(msg, "empoignade-roll-data", rollData)
RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
}
/* -------------------------------------------- */
static async onDefenseEmpoignade(rollData, defenseMode, competenceName = "Corps à corps", carac = "melee") {
let attacker = game.actors.get(rollData.attackerId)
let defender = game.actors.get(rollData.defenderId)
static async onDefenseEmpoignade(attackerRoll, mode, competenceName = "Corps à corps", carac = "melee") {
let attacker = game.actors.get(attackerRoll.attacker.id)
let defender = game.actors.get(attackerRoll.defender.id)
if (!RdDEmpoignade.isActionAutorisee(mode, attacker, defender)) {
return
}
let empoignade = this.getEmpoignade(attacker, defender)
if (!empoignade) {
@ -156,18 +268,23 @@ export class RdDEmpoignade {
}
empoignade = duplicate(empoignade)
rollData.mode = defenseMode
rollData.empoignade = empoignade
rollData.competence = defender.getCompetence(competenceName),
rollData.selectedCarac = defender.system.carac[carac],
rollData.malusTaille = RdDEmpoignade.getMalusTaille(empoignade, defender, attacker)
await RdDEmpoignade.$rollDefenseEmpoignade(defender, rollData);
let defenderRoll = {
mode, attacker, defender, empoignade, attackerRoll,
diffLibre: attackerRoll.diffLibre,
attaqueParticuliere: attackerRoll.particuliere,
competence: defender.getCompetence(competenceName).clone(),
surprise: defender.getSurprise(true),
carac: defender.system.carac,
selectedCarac: defender.system.carac[carac],
malusTaille: RdDEmpoignade.getMalusTaille(empoignade, defender, attacker),
show: {}
};
await RdDEmpoignade.$rollDefenseEmpoignade(defender, defenderRoll);
}
/* -------------------------------------------- */
static async $rollDefenseEmpoignade(defender, rollData) {
const dialog = await RdDRoll.create(defender, rollData,
static async $rollDefenseEmpoignade(defender, defenderRoll) {
const dialog = await RdDRoll.create(defender, defenderRoll,
{ html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-defense-empoignade.html' },
{
name: 'empoignade',
@ -183,7 +300,7 @@ export class RdDEmpoignade {
/* -------------------------------------------- */
static async $onRollContrerLiberer(rollData) {
let empoignade = rollData.empoignade
if (rollData.mode == "contrer-empoigner" && !rollData.rolled.isSuccess) {
empoignade.system.pointsemp++
RdDEmpoignade.$updateEtatEmpoignade(empoignade)
@ -192,13 +309,12 @@ export class RdDEmpoignade {
empoignade.system.pointsemp--
RdDEmpoignade.$updateEtatEmpoignade(empoignade)
}
if (empoignade.system.pointsemp >= 2) {
let attacker = game.actors.get(empoignade.system.empoigneurid)
let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-actions.html');
ChatUtility.setMessageData(msg, "empoignade-roll-data", rollData)
}
await RdDResolutionTable.displayRollData(rollData, rollData.defender, 'chat-empoignade-resultat.html')
if (empoignade.system.pointsemp >= 2) {
let msg = await RdDResolutionTable.displayRollData(rollData, rollData.attacker, 'chat-empoignade-entrainer.html');
RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
}
}
/* -------------------------------------------- */
@ -223,16 +339,15 @@ export class RdDEmpoignade {
let defender = game.actors.get(empoignade.system.empoigneid)
let emp = RdDEmpoignade.getEmpoignadeById(defender, empoignade.system.empoignadeid)
await defender.deleteEmbeddedDocuments('Item', [emp._id])
//let attacker = game.actors.get(empoignade.system.empoigneurid)
//emp = RdDEmpoignade.getEmpoignadeById(attacker, empoignade.system.empoignadeid)
//await attacker.deleteEmbeddedDocuments('Item', [emp._id])
}
/* -------------------------------------------- */
static async entrainerAuSol(rollData) {
let attacker = game.actors.get(rollData.attackerId)
let defender = game.actors.get(rollData.defenderId)
let attacker = game.actors.get(rollData.attacker.id)
let defender = game.actors.get(rollData.defender.id)
if (!RdDEmpoignade.isActionAutorisee("immobilise", attacker, defender)) {
return
}
let empoignade = this.getEmpoignade(attacker, defender)
empoignade.system.ausol = true
@ -242,25 +357,32 @@ export class RdDEmpoignade {
await defender.setEffect(STATUSES.StatusProne, true);
let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-entrainer-sol.html');
ChatUtility.setMessageData(msg, "empoignade-roll-data", rollData)
RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
}
/* -------------------------------------------- */
static async projeterAuSol(rollData) {
let attacker = game.actors.get(rollData.attackerId)
let defender = game.actors.get(rollData.defenderId)
let attacker = game.actors.get(rollData.attacker.id)
let defender = game.actors.get(rollData.defender.id)
if (!RdDEmpoignade.isActionAutorisee("immobilise", attacker, defender)) {
return
}
let empoignade = this.getEmpoignade(attacker, defender)
await defender.setEffect(STATUSES.StatusProne, true);
await this.$deleteEmpoignade(empoignade)
let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-projeter-sol.html');
ChatUtility.setMessageData(msg, "empoignade-roll-data", rollData)
RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
}
/* -------------------------------------------- */
static async perteEndurance(rollData, perteMode) {
let attacker = game.actors.get(rollData.attackerId)
let defender = game.actors.get(rollData.defenderId)
let attacker = game.actors.get(rollData.attacker.id)
let defender = game.actors.get(rollData.defender.id)
if (!RdDEmpoignade.isActionAutorisee("immobilise", attacker, defender)) {
return
}
let empoignade = this.getEmpoignade(attacker, defender)
//console.log("Perte d'endurance :!!!", perteMode)
@ -278,7 +400,7 @@ export class RdDEmpoignade {
await defender.santeIncDec("endurance", -(3 * Math.floor(endValue / 4)));
}
let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-perte-endurance.html');
ChatUtility.setMessageData(msg, "empoignade-roll-data", rollData)
RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
}
/* -------------------------------------------- */

View File

@ -91,13 +91,17 @@ export class RdDResolutionTable {
/* -------------------------------------------- */
static async displayRollData(rollData, actor = undefined, template = 'chat-resultat-general.html') {
return await ChatUtility.createChatWithRollMode(actor?.userName ?? game.user.name, {
content: await RdDResolutionTable.buildRollDataHtml(rollData, actor, template)
return await ChatUtility.createChatWithRollMode(RdDResolutionTable.actorChatName(actor), {
content: await RdDResolutionTable.buildRollDataHtml(rollData, template)
});
}
static actorChatName(actor) {
return actor?.userName ?? game.user.name;
}
/* -------------------------------------------- */
static async buildRollDataHtml(rollData, actor, template = 'chat-resultat-general.html') {
static async buildRollDataHtml(rollData, template = 'chat-resultat-general.html') {
rollData.show = rollData.show || {};
return await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/${template}`, rollData);
}

View File

@ -668,6 +668,7 @@ export class RdDUtility {
/* -------------------------------------------- */
static async chatListeners(html) {
RdDCombat.registerChatCallbacks(html);
RdDEmpoignade.registerChatCallbacks(html);
// Gestion spécifique message passeurs
html.on("click", '.tmr-passeur-coord a', event => {
@ -694,44 +695,6 @@ export class RdDUtility {
RdDPossession.onDefensePossession(attackerId, defenderId, possessionId)
});
html.on("click", '.defense-empoignade-cac', event => {
const chatMessage = ChatUtility.getChatMessage(event);
const rollData = ChatUtility.getMessageData(chatMessage, 'empoignade-roll-data');
let defenseMode = event.currentTarget.attributes['data-defense-mode'].value
RdDEmpoignade.onDefenseEmpoignade(rollData, defenseMode, "Corps à corps", "melee")
});
html.on("click", '.defense-empoignade-esquive', event => {
const chatMessage = ChatUtility.getChatMessage(event);
const rollData = ChatUtility.getMessageData(chatMessage, 'empoignade-roll-data');
let defenseMode = event.currentTarget.attributes['data-defense-mode'].value
RdDEmpoignade.onDefenseEmpoignade(rollData, defenseMode, "Esquive", "derobee")
});
html.on("click", '.empoignade-poursuivre', event => {
let attackerId = event.currentTarget.attributes['data-attackerId'].value
let defenderId = event.currentTarget.attributes['data-defenderId'].value
RdDEmpoignade.onAttaqueEmpoignadeValidee(game.actors.get(attackerId), game.actors.get(defenderId))
});
html.on("click", '.empoignade-entrainer-sol', event => {
const chatMessage = ChatUtility.getChatMessage(event);
const rollData = ChatUtility.getMessageData(chatMessage, 'empoignade-roll-data');
RdDEmpoignade.entrainerAuSol(rollData)
ChatUtility.removeChatMessageId(chatMessage.id)
});
html.on("click", '.empoignade-projeter-sol', event => {
const chatMessage = ChatUtility.getChatMessage(event);
const rollData = ChatUtility.getMessageData(chatMessage, 'empoignade-roll-data');
RdDEmpoignade.projeterAuSol(rollData)
ChatUtility.removeChatMessageId(chatMessage.id)
});
html.on("change", '.empoignade-perte-endurance', event => {
const chatMessage = ChatUtility.getChatMessage(event);
const rollData = ChatUtility.getMessageData(chatMessage, 'empoignade-roll-data');
if (event.currentTarget.value && event.currentTarget.value != "none") {
RdDEmpoignade.perteEndurance(rollData, event.currentTarget.value)
ChatUtility.removeChatMessageId(chatMessage.id)
}
});
// gestion bouton tchat Acheter
html.on("click", '.button-acheter', event => {
const venteData = DialogItemAchat.preparerAchat(event.currentTarget);

View File

@ -1,8 +1,8 @@
{
"id": "foundryvtt-reve-de-dragon",
"title": "Rêve de Dragon",
"version": "10.7.19",
"download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-10.7.19.zip",
"version": "10.7.21",
"download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-10.7.21.zip",
"manifest": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/v10/system.json",
"compatibility": {
"minimum": "10",

View File

@ -1,39 +0,0 @@
<img class="chat-icon" src="{{competence.img}}" />
<h4>
{{attackerName}} a empoigné {{defenderName}}
</h4>
<hr>
<div>
<span class='chat-card-button-area'>
Au round suivant l'acquisition des 2 points d'Emp, {{attackerName}} peut faire perdre autant de points d'Endurance qu'il souhaite à {{defenderName}}
<br>
<a class='empoignade-perte-endurance chat-card-button'>
<select class='empoignade-perte-endurance'>
<option value="none">Faire perdre de l'endurance (selectionnez)</option>
<option value="end0">Endurance à 0</option>
<option value="end1">Endurance à 1</option>
<option value="endmoitie">La moitié de l'endurance</option>
<option value="endquart">Le quart de l'endurance</option>
</select>
</a>
{{#if empoignade.system.ausol}}
{{else}}
<br>
Dès l'acquisition des 2 points d'Emp, {{attackerName}} peut entraîner {{defenderName}} au sol. Les deux protagonistes restent empoignés.
<br>
<a class='empoignade-entrainer-sol chat-card-button'>
Entraîner au sol
</a>
<br>
A la fin du round ou les 2 points d'Emp sont acquis, {{attackerName}} peut projeter {{defenderName}} au sol. Les deux protagonistes ne sont plus empoignés.
<br>
<a class='empoignade-projeter-sol chat-card-button'>
Projeter au sol
</a>
{{/if}}
</div>

View File

@ -1,7 +1,8 @@
<img class="chat-icon" src="{{competence.img}}" />
<h4>
{{attackerName}} a entraîné {{defenderName}} au sol. L'empoignade peut continuer.
{{attacker.name}} a entraîné {{defender.name}} au sol
</h4>
<hr>
<div>
L'empoignade peut continuer.
</div>

View File

@ -0,0 +1,16 @@
<img class="chat-icon" src="{{competence.img}}" />
<h4>
{{attacker.name}} a empoigné {{defender.name}}
</h4>
<hr>
<div>
<span class='chat-card-button-area'>
{{attacker.name}} vient d'obtenir 2 points d'Emp, et peut
entraîner {{defender.name}} au sol. Les deux protagonistes
restent empoignés.
<br>
<a class='empoignade-entrainer-sol chat-card-button'>
Entraîner au sol
</a>
</span>
</div>

View File

@ -0,0 +1,35 @@
<img class="chat-icon" src="{{competence.img}}" />
<h4>
{{attacker.name}} a empoigné {{defender.name}}
</h4>
<hr>
<div>
<span class='chat-card-button-area'>
<p>
{{attacker.name}} a obtenu 2 points d'Emp à la fin du round précédent, et peut:
<ul><li>
faire perdre des points d'Endurance à {{defender.name}}
<br>
<a class='empoignade-perte-endurance chat-card-button'>
<select class='empoignade-perte-endurance'>
<option value="none">Faire perdre de l'endurance (selectionnez)</option>
<option value="end0">Endurance à 0</option>
<option value="end1">Endurance à 1</option>
<option value="endmoitie">La moitié de l'endurance</option>
<option value="endquart">Le quart de l'endurance</option>
</select>
</a>
{{#if empoignade.system.ausol}}
{{else}}
</li><li>
projeter {{defender.name}} au sol. Les deux protagonistes ne sont plus empoignés.
<br>
<a class='empoignade-projeter-sol chat-card-button'>
Projeter au sol
</a>
{{/if}}
</li></ul>
</p>
</span>
</div>

View File

@ -1,7 +1,8 @@
<img class="chat-icon" src="{{competence.img}}" />
<h4>
{{attackerName}} a fait perdre de l'endurance à {{defenderName}}, qui reste immobilisé. L'empoignade peut continuer.
{{attacker.name}} a fait perdre de l'endurance à {{defender.name}}
</h4>
<hr>
<div>
{{defender.name}} reste immobilisé. L'empoignade peut continuer.
</div>

View File

@ -1,7 +1,8 @@
<img class="chat-icon" src="{{competence.img}}" />
<h4>
{{attackerName}} a projeté {{defenderName}} au sol. L'empoignade est terminée et a été supprimée.
{{attacker.name}} a projeté {{defender.name}} au sol
</h4>
<hr>
<div>
L'empoignade est terminée et a été supprimée.
</div>

View File

@ -1,16 +1,17 @@
<img class="chat-icon" src="{{competence.img}}" />
<h4>
{{log 'rollData' this}}
{{#if (eq mode "empoigner")}}
{{attackerName}} tente d'empoigner {{defenderName}}
{{attacker.name}} tente d'empoigner {{defender.name}}
{{/if}}
{{#if (eq mode "contrer-empoigner")}}
{{defenderName}} tente de contrer l'empoignade de {{attackerName}}
{{defender.name}} tente de contrer l'empoignade de {{attacker.name}}
{{/if}}
{{#if (eq mode "liberer")}}
{{attackerName}} tente de se libérer de l'empoignade de {{defenderName}}
{{attacker.name}} tente de se libérer de l'empoignade de {{defender.name}}
{{/if}}
{{#if (eq mode "contrer-liberer")}}
{{defenderName}} tente de contrer la libération de {{attackerName}}
{{defender.name}} tente de contrer la libération de {{attacker.name}}
{{/if}}
</h4>
{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.html"}}
@ -20,7 +21,7 @@
{{#if (gte empoignade.system.pointsemp 2)}}
<br><strong>{{defenderName}} est empoigné et immobilisé par {{attackerName}} !</strong>
<br><strong>{{defender.name}} est empoigné et immobilisé par {{attacker.name}} !</strong>
{{else}}
<span class='chat-card-button-area'>
@ -29,16 +30,12 @@
{{#if (eq mode "empoigner")}}
{{#if empoignade.isSuccess}}
<a class='defense-empoignade-cac chat-card-button'
data-attackerId='{{attacker.id}}'
data-defenderId='{{defender.id}}'
data-diff-libre='{{diffLibre}}'
data-defense-mode="contrer-empoigner">
Contrer l'empoignade (Corps à Corps)
</a>
{{#if (eq empoignade.system.pointsemp 0)}}
<a class='defense-empoignade-esquive chat-card-button'
data-attackerId='{{attacker.id}}'
data-defenderId='{{defender.id}}'
data-diff-libre='{{diffLibre}}'
data-defense-mode="contrer-empoigner">
Contrer l'empoignade (Esquive)
@ -52,8 +49,6 @@
{{#if (eq mode "liberer")}}
{{#if empoignade.isSuccess}}
<a class='defense-empoignade-cac chat-card-button'
data-attackerId='{{attacker.id}}'
data-defenderId='{{defender.id}}'
data-diff-libre='{{diffLibre}}'
data-defense-mode="contrer-liberer">
Contrer la libération (Corps à Corps)
@ -78,8 +73,7 @@
La tentative de contrer la libération est un échec!
{{/if}}
{{/if}}
<br>Points d'Emp: {{empoignade.system.pointsemp}}
</span>
<br>Points d'Emp: {{empoignade.system.pointsemp}}
{{/if}}
</div>

View File

@ -1,10 +1,9 @@
<img class="chat-icon" src="{{competence.img}}" />
<h4>
{{attackerName}} tente d'empoigner {{defenderName}}
{{attacker.name}} tente d'empoigner {{defender.name}}
</h4>
<hr>
<div>
<span class='chat-card-button-area'>
<br>
<strong>{{attacker.name}} tente d'empoigner {{defender.name}}, qui est équipé d'une arme de mêlée. {{defender.name}}
@ -16,5 +15,5 @@
data-defenderId='{{defender.id}}'>
Poursuivre l'empoignade
</a>
</span>
</div>

View File

@ -1,6 +1,6 @@
<form class="skill-roll-dialog">
<h2>
{{defenderName}} tente de contrer l'empoignade de {{attackerName}}
{{defender.name}} tente de contrer l'empoignade de {{attacker.name}}
</h2>
<div class="grid grid-2col">
<div class="flex-group-left">