Gestion de l'empoignade

This commit is contained in:
LeRatierBretonnien 2023-04-21 18:18:20 +02:00
parent a096590a07
commit c0e6759164
21 changed files with 658 additions and 19 deletions

View File

@ -14,6 +14,7 @@ import { MAINS_DIRECTRICES } from "./actor.js";
import { RdDBaseActorSheet } from "./actor/base-actor-sheet.js"; import { RdDBaseActorSheet } from "./actor/base-actor-sheet.js";
import { RdDItem } from "./item.js"; import { RdDItem } from "./item.js";
import { RdDItemBlessure } from "./item/blessure.js"; import { RdDItemBlessure } from "./item/blessure.js";
import { RdDEmpoignade } from "./rdd-empoignade.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
/** /**
@ -83,6 +84,7 @@ export class RdDActorSheet extends RdDBaseActorSheet {
RdDItemArme.ajoutCorpsACorps(formData.combat, formData.competences, formData.system.carac); RdDItemArme.ajoutCorpsACorps(formData.combat, formData.competences, formData.system.carac);
formData.esquives = this.actor.getCompetences("Esquive"); formData.esquives = this.actor.getCompetences("Esquive");
formData.combat = RdDCombatManager.listActionsArmes(formData.combat, formData.competences, formData.system.carac); formData.combat = RdDCombatManager.listActionsArmes(formData.combat, formData.competences, formData.system.carac);
formData.empoignades = this.actor.getEmpoignades("Esquive");
this.armesList = formData.combat; this.armesList = formData.combat;
@ -254,6 +256,11 @@ export class RdDActorSheet extends RdDBaseActorSheet {
this.actor.rollCarac('reve-actuel', true); this.actor.rollCarac('reve-actuel', true);
}); });
// Suite empoignade
this.html.find('.empoignade-label a').click(async event => {
let emp = RdDSheetUtility.getItem(event, this.actor)
RdDEmpoignade.onAttaqueEmpoignadeFromItem(emp)
});
// Roll Weapon1 // Roll Weapon1
this.html.find('.arme-label a').click(async event => { this.html.find('.arme-label a').click(async event => {
let arme = this._getEventArmeCombat(event); let arme = this._getEventArmeCombat(event);

View File

@ -36,6 +36,7 @@ import { RdDBaseActor } from "./actor/base-actor.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js"; import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { RdDItemBlessure } from "./item/blessure.js"; import { RdDItemBlessure } from "./item/blessure.js";
import { AppAstrologie } from "./sommeil/app-astrologie.js"; import { AppAstrologie } from "./sommeil/app-astrologie.js";
import { RdDEmpoignade } from "./rdd-empoignade.js";
const POSSESSION_SANS_DRACONIC = { const POSSESSION_SANS_DRACONIC = {
img: 'systems/foundryvtt-reve-de-dragon/icons/entites/possession.webp', img: 'systems/foundryvtt-reve-de-dragon/icons/entites/possession.webp',
@ -231,7 +232,6 @@ export class RdDActor extends RdDBaseActor {
getCompetences(name) { getCompetences(name) {
return RdDItemCompetence.findCompetences(this.items, name) return RdDItemCompetence.findCompetences(this.items, name)
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
getTache(id) { getTache(id) {
return this.findItemLike(id, 'tache'); return this.findItemLike(id, 'tache');
@ -286,7 +286,9 @@ export class RdDActor extends RdDBaseActor {
getPossessions() { getPossessions() {
return this.items.filter(it => it.type == 'possession'); return this.items.filter(it => it.type == 'possession');
} }
getEmpoignades() {
return this.items.filter(it => it.type == 'empoignade');
}
getDemiReve() { getDemiReve() {
return this.system.reve.tmrpos.coord; return this.system.reve.tmrpos.coord;
} }
@ -329,8 +331,21 @@ export class RdDActor extends RdDBaseActor {
return ''; return '';
} }
/* -------------------------------------------- */
hasArmeeMeleeEquipee() { // Return true si l'acteur possède au moins 1 arme de mêlée équipée
let melee = this.items.filter(it => it.type == "arme" && it.system.equipe && it.system.competence != "")
return (melee.length > 0)
}
isEmpoignadeEnCours() {
return this.items.find(it => it.type == "empoignade" && it.system.pointsemp > 0)
}
/* -------------------------------------------- */ /* -------------------------------------------- */
async roll() { async roll() {
if (this.isEmpoignadeEnCours()) {
ui.notifications.warn("Une empoignade est en cours ! Normalement, vous ne pouvez rien faire d'autre que continuer l'empoignade ou la rompre.")
}
const carac = mergeObject(duplicate(this.system.carac), const carac = mergeObject(duplicate(this.system.carac),
{ {
'reve-actuel': this.getCaracReveActuel(), 'reve-actuel': this.getCaracReveActuel(),
@ -2061,6 +2076,10 @@ export class RdDActor extends RdDBaseActor {
/* -------------------------------------------- */ /* -------------------------------------------- */
async rollUnSort(coord) { async rollUnSort(coord) {
if (this.isEmpoignadeEnCours()) {
ui.notifications.warn("Une empoignade est en cours ! Normalement, vous ne pouvez rien faire d'autre que continuer l'empoignade ou la rompre.")
}
if (EffetsDraconiques.isSortImpossible(this)) { if (EffetsDraconiques.isSortImpossible(this)) {
ui.notifications.error("Une queue ou un souffle vous empèche de lancer de sort!"); ui.notifications.error("Une queue ou un souffle vous empèche de lancer de sort!");
return; return;
@ -2200,6 +2219,10 @@ export class RdDActor extends RdDBaseActor {
/* -------------------------------------------- */ /* -------------------------------------------- */
async rollCarac(caracName, jetResistance = undefined) { async rollCarac(caracName, jetResistance = undefined) {
if (this.isEmpoignadeEnCours()) {
ui.notifications.warn("Une empoignade est en cours ! Normalement, vous ne pouvez rien faire d'autre que continuer l'empoignade ou la rompre.")
}
let selectedCarac = this.getCaracByName(caracName) let selectedCarac = this.getCaracByName(caracName)
await this._openRollDialog({ await this._openRollDialog({
name: 'jet-' + caracName, name: 'jet-' + caracName,
@ -2267,6 +2290,10 @@ export class RdDActor extends RdDBaseActor {
/* -------------------------------------------- */ /* -------------------------------------------- */
async rollCompetence(idOrName, options = { tryTarget: true }) { async rollCompetence(idOrName, options = { tryTarget: true }) {
if (this.isEmpoignadeEnCours()) {
ui.notifications.warn("Une empoignade est en cours ! Normalement, vous ne pouvez rien faire d'autre que continuer l'empoignade ou la rompre.")
}
let rollData = { let rollData = {
carac: this.system.carac, carac: this.system.carac,
competence: this.getCompetence(idOrName) competence: this.getCompetence(idOrName)
@ -2347,6 +2374,10 @@ export class RdDActor extends RdDBaseActor {
} }
async rollCaracCompetence(caracName, compName, diff, options = { title: "" }) { async rollCaracCompetence(caracName, compName, diff, options = { title: "" }) {
if (this.isEmpoignadeEnCours()) {
ui.notifications.warn("Une empoignade est en cours ! Normalement, vous ne pouvez rien faire d'autre que continuer l'empoignade ou la rompre.")
}
const competence = this.getCompetence(compName); const competence = this.getCompetence(compName);
await this._openRollDialog({ await this._openRollDialog({
name: 'jet-competence', name: 'jet-competence',
@ -2367,6 +2398,10 @@ export class RdDActor extends RdDBaseActor {
/* -------------------------------------------- */ /* -------------------------------------------- */
async rollTache(id, options = {}) { async rollTache(id, options = {}) {
if (this.isEmpoignadeEnCours()) {
ui.notifications.warn("Une empoignade est en cours ! Normalement, vous ne pouvez rien faire d'autre que continuer l'empoignade ou la rompre.")
}
const tacheData = this.getTache(id) const tacheData = this.getTache(id)
const compData = this.getCompetence(tacheData.system.competence) const compData = this.getCompetence(tacheData.system.competence)
compData.system.defaut_carac = tacheData.system.carac; // Patch ! compData.system.defaut_carac = tacheData.system.carac; // Patch !
@ -3754,6 +3789,9 @@ export class RdDActor extends RdDBaseActor {
case 'casetmr': case 'casetmr':
await this.onDeleteOwnedCaseTmr(item, options, id); await this.onDeleteOwnedCaseTmr(item, options, id);
break; break;
case 'empoignade':
await RdDEmpoignade.deleteLinkedEmpoignade(this.id, item)
break;
} }
} }

View File

@ -165,7 +165,7 @@ export class RdDItemArme extends Item {
let corpsACorps = competences.find(it => it.name == 'Corps à corps') ?? { system: { niveau: -6 } }; let corpsACorps = competences.find(it => it.name == 'Corps à corps') ?? { system: { niveau: -6 } };
let init = RdDCombatManager.calculInitiative(corpsACorps.system.niveau, carac['melee'].value); let init = RdDCombatManager.calculInitiative(corpsACorps.system.niveau, carac['melee'].value);
armes.push(RdDItemArme.mainsNues({ niveau: corpsACorps.system.niveau, initiative: init })); armes.push(RdDItemArme.mainsNues({ niveau: corpsACorps.system.niveau, initiative: init }));
//armes.push(RdDItemArme.empoignade({ niveau: corpsACorps.system.niveau, initiative: init })); armes.push(RdDItemArme.empoignade({ niveau: corpsACorps.system.niveau, initiative: init }));
} }
static corpsACorps(mainsNuesActor) { static corpsACorps(mainsNuesActor) {

View File

@ -75,6 +75,7 @@ export const defaultItemImg = {
sortreserve: "systems/foundryvtt-reve-de-dragon/icons/competence_oniros.webp", sortreserve: "systems/foundryvtt-reve-de-dragon/icons/competence_oniros.webp",
extraitpoetique: "systems/foundryvtt-reve-de-dragon/icons/competence_ecriture.webp", extraitpoetique: "systems/foundryvtt-reve-de-dragon/icons/competence_ecriture.webp",
tarot: "systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.webp", tarot: "systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.webp",
empoignade: "systems/foundryvtt-reve-de-dragon/icons/competence_corps_a_corps.webp"
} }
/* -------------------------------------------- */ /* -------------------------------------------- */

View File

@ -24,6 +24,9 @@ export class RdDBonus {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static isDefenseAttaqueFinesse(rollData) { static isDefenseAttaqueFinesse(rollData) {
if (rollData.isEmpoignade && rollData.rolled?.isPart) {
return true
}
return rollData.attackerRoll?.particuliere == 'finesse'; return rollData.attackerRoll?.particuliere == 'finesse';
} }

View File

@ -12,6 +12,7 @@ import { RdDRollTables } from "./rdd-rolltables.js";
import { ReglesOptionelles } from "./settings/regles-optionelles.js"; import { ReglesOptionelles } from "./settings/regles-optionelles.js";
import { STATUSES } from "./settings/status-effects.js"; import { STATUSES } from "./settings/status-effects.js";
import { Targets } from "./targets.js"; import { Targets } from "./targets.js";
import { RdDEmpoignade } from "./rdd-empoignade.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
const premierRoundInit = [ const premierRoundInit = [
@ -57,6 +58,7 @@ export class RdDCombatManager extends Combat {
ChatUtility.removeChatMessageContaining(`<div data-combatid="${this.id}" data-combatmessage="actor-turn-summary">`) ChatUtility.removeChatMessageContaining(`<div data-combatid="${this.id}" data-combatmessage="actor-turn-summary">`)
game.messages.filter(m => ChatUtility.getMessageData(m, 'attacker-roll') != undefined && ChatUtility.getMessageData(m, 'defender-roll') != undefined) game.messages.filter(m => ChatUtility.getMessageData(m, 'attacker-roll') != undefined && ChatUtility.getMessageData(m, 'defender-roll') != undefined)
.forEach(it => it.delete()); .forEach(it => it.delete());
RdDEmpoignade.deleteAllEmpoignades()
} }
} }
@ -91,13 +93,26 @@ export class RdDCombatManager extends Combat {
} }
} else { } else {
const armeCombat = combatant.actor.itemTypes['arme'].find(it => it.system.equipe) const armeCombat = combatant.actor.itemTypes['arme'].find(it => it.system.equipe)
const compName = (armeCombat == undefined) ? "Corps à corps" : armeCombat.system.competence; let compName = "Corps à corps"
if (armeCombat) {
if (armeCombat.system.competence != "") {
compName = armeCombat.system.competence
}
if (armeCombat.system.lancer != "") {
compName = armeCombat.system.lancer
}
if (armeCombat.system.tir != "") {
compName = armeCombat.system.tir
}
}
const competence = RdDItemCompetence.findCompetence(combatant.actor.items, compName); const competence = RdDItemCompetence.findCompetence(combatant.actor.items, compName);
if (competence) { if (competence && competence.system.defaut_carac) {
const carac = combatant.actor.system.carac[competence.system.defaut_carac].value; const carac = combatant.actor.system.carac[competence.system.defaut_carac].value;
const niveau = competence.system.niveau; const niveau = competence.system.niveau;
const bonusEcaille = (armeCombat?.system.magique) ? armeCombat.system.ecaille_efficacite : 0; const bonusEcaille = (armeCombat?.system.magique) ? armeCombat.system.ecaille_efficacite : 0;
rollFormula = RdDCombatManager.formuleInitiative(2, carac, niveau, bonusEcaille); rollFormula = RdDCombatManager.formuleInitiative(2, carac, niveau, bonusEcaille);
} else {
ui.notifications.warn(`Votre arme ${armeCombat.name} n'a pas de compétence renseignée`);
} }
} }
} }
@ -244,7 +259,7 @@ export class RdDCombatManager extends Combat {
} else if (actor.isPersonnage()) { } else if (actor.isPersonnage()) {
// Recupération des items 'arme' // Recupération des items 'arme'
const armes = actor.itemTypes['arme'].filter(it => RdDItemArme.isArmeUtilisable(it)) const armes = actor.itemTypes['arme'].filter(it => RdDItemArme.isArmeUtilisable(it))
//.concat(RdDItemArme.empoignade()) .concat(RdDItemArme.empoignade())
.concat(RdDItemArme.mainsNues()); .concat(RdDItemArme.mainsNues());
const competences = actor.itemTypes['competence']; const competences = actor.itemTypes['competence'];
@ -737,17 +752,13 @@ export class RdDCombat {
if (!await this.attacker.accorder(this.defender, 'avant-attaque')) { if (!await this.attacker.accorder(this.defender, 'avant-attaque')) {
return; return;
} }
if (arme.system.cac == 'empoignade' && this.attacker.isCombatTouche()) { if (arme.system.cac == 'empoignade') {
ChatMessage.create({ RdDEmpoignade.onAttaqueEmpoignade(this.attacker, this.defender)
alias: this.attacker.name,
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.attacker.name),
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-actor-perte-empoignade.html', {
attacker: this.attacker,
competence: competence
})
});
return; return;
} }
if ( this.attacker.isEmpoignadeEnCours() ) {
ui.notifications.warn("Une empoignade est en cours ! Normalement, vous ne pouvez rien faire d'autre que continuer l'empoignade ou la rompre.")
}
let rollData = this._prepareAttaque(competence, arme); let rollData = this._prepareAttaque(competence, arme);
console.log("RdDCombat.attaque >>>", rollData); console.log("RdDCombat.attaque >>>", rollData);

301
module/rdd-empoignade.js Normal file
View File

@ -0,0 +1,301 @@
/* -------------------------------------------- */
import { RdDCombat } from "./rdd-combat.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDRoll } from "./rdd-roll.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { ChatUtility } from "./chat-utility.js";
import { STATUSES, StatusEffects } from "./settings/status-effects.js";
/* -------------------------------------------- */
/* -------------------------------------------- */
export class RdDEmpoignade {
/* -------------------------------------------- */
static init() {
}
/* -------------------------------------------- */
static getEmpoignadeById(actor, id) {
let emp = actor.items.find(emp => emp.type == 'empoignade' && emp.system.empoignadeid == id)
return emp && duplicate(emp) || undefined;
}
/* -------------------------------------------- */
static getEmpoignade(attacker, defender) {
let emp = attacker.items.find(emp => emp.type == 'empoignade' && emp.system.empoigneurid == attacker.id && emp.system.empoigneid == defender.id)
if (!emp) {
emp = attacker.items.find(emp => emp.type == 'empoignade' && emp.system.empoigneurid == defender.id && emp.system.empoigneid == attacker.id)
}
if (emp) {
// TODO ? central storage ?
}
return emp && duplicate(emp) || 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)
}
return 0
}
/* -------------------------------------------- */
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"
let rollData = {
mode: mode,
isEmpoignade: true,
competence: attacker.getCompetence("Corps à corps"),
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 async onAttaqueEmpoignade(attacker, defender) {
let empoignade = RdDEmpoignade.getEmpoignade(attacker, defender)
const isNouvelle = empoignade == undefined;
empoignade = empoignade ?? (await RdDEmpoignade.createEmpoignade(attacker, defender))
//console.log("W.", empoignade, defender.hasArmeeMeleeEquipee())
if ((isNouvelle || empoignade.system.pointsemp == 0) && defender.hasArmeeMeleeEquipee()) {
ChatUtility.createChatWithRollMode(attacker.name, {
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-empoignade-valider.html`, { attacker: attacker, defender: defender })
})
} else {
await this.onAttaqueEmpoignadeValidee(attacker, defender)
}
}
/* -------------------------------------------- */
static async onAttaqueEmpoignadeFromItem(empoignade) {
let attacker = game.actors.get(empoignade.system.empoigneurid)
let defender = game.actors.get(empoignade.system.empoigneid)
await this.onAttaqueEmpoignadeValidee(attacker, defender)
}
/* -------------------------------------------- */
static async $rollAttaqueEmpoignade(attacker, rollData, isNouvelle = false) {
const dialog = await RdDRoll.create(attacker, rollData,
{ html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html' },
{
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) },
]
});
dialog.render(true);
}
/* -------------------------------------------- */
static async $onRollEmpoignade(rollData, isSuccess, isNouvelle = false) {
let attacker = game.actors.get(rollData.attackerId)
let defender = game.actors.get(rollData.defenderId)
let empoignade = rollData.empoignade
empoignade.isSuccess = isSuccess;
if (isSuccess && isNouvelle) {
// Creer l'empoignade sur attaquant/defenseur
await attacker.createEmbeddedDocuments('Item', [empoignade.toObject()])
await defender.createEmbeddedDocuments('Item', [empoignade.toObject()])
}
let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-resultat.html');
ChatUtility.setMessageData(msg, "empoignade-roll-data", 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)
let empoignade = this.getEmpoignade(attacker, defender)
if (!empoignade) {
ui.notifications.warn("Une erreur s'est produite : Aucune empoignade trouvée !!")
return
}
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);
}
/* -------------------------------------------- */
static async $rollDefenseEmpoignade(defender, rollData) {
const dialog = await RdDRoll.create(defender, rollData,
{ html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-defense-empoignade.html' },
{
name: 'empoignade',
label: 'Contrer',
callbacks: [
{ action: async (r) => await RdDEmpoignade.$onRollContrerLiberer(r) }
]
}
);
dialog.render(true);
}
/* -------------------------------------------- */
static async $onRollContrerLiberer(rollData) {
let empoignade = rollData.empoignade
if (rollData.mode == "contrer-empoigner" && !rollData.rolled.isSuccess) {
empoignade.system.pointsemp++
RdDEmpoignade.$updateEtatEmpoignade(empoignade)
}
if (rollData.mode == "contrer-liberer" && !rollData.rolled.isSuccess) {
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')
}
/* -------------------------------------------- */
static async $updateEtatEmpoignade(empoignade) {
console.log("UPDATE Empoignade", empoignade)
let defender = game.actors.get(empoignade.system.empoigneid)
let emp = RdDEmpoignade.getEmpoignadeById(defender, empoignade.system.empoignadeid)
let update = { _id: emp._id, "system.pointsemp": empoignade.system.pointsemp, "system.ausol": empoignade.system.ausol }
await defender.updateEmbeddedDocuments('Item', [update])
let attacker = game.actors.get(empoignade.system.empoigneurid)
emp = RdDEmpoignade.getEmpoignadeById(attacker, empoignade.system.empoignadeid)
update = { _id: emp._id, "system.pointsemp": empoignade.system.pointsemp, "system.ausol": empoignade.system.ausol }
await attacker.updateEmbeddedDocuments('Item', [update])
}
/* -------------------------------------------- */
static async $deleteEmpoignade(empoignade) {
console.log("DELETE Empoignade", empoignade)
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 empoignade = this.getEmpoignade(attacker, defender)
empoignade.system.ausol = true
await this.$updateEtatEmpoignade(empoignade)
await attacker.setEffect(STATUSES.StatusProne, true);
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)
}
/* -------------------------------------------- */
static async projeterAuSol(rollData) {
let attacker = game.actors.get(rollData.attackerId)
let defender = game.actors.get(rollData.defenderId)
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)
}
/* -------------------------------------------- */
static async perteEndurance(rollData, perteMode) {
let attacker = game.actors.get(rollData.attackerId)
let defender = game.actors.get(rollData.defenderId)
let empoignade = this.getEmpoignade(attacker, defender)
console.log("Perte d'endurance :!!!", perteMode)
let endValue = defender.system.sante.endurance.value
if (perteMode == "end0") {
await defender.santeIncDec("endurance", -defender.system.sante.endurance.value);
}
if (perteMode == "end1") {
await defender.santeIncDec("endurance", -(defender.system.sante.endurance.value - 1));
}
if (perteMode == "endmoitie") {
await defender.santeIncDec("endurance", -Math.floor(defender.system.sante.endurance.value / 2));
}
if (perteMode == "endquart") {
await defender.santeIncDec("endurance", -(3 * Math.floor(defender.system.sante.endurance.value / 4)));
}
let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-perte-endurance.html');
ChatUtility.setMessageData(msg, "empoignade-roll-data", rollData)
}
/* -------------------------------------------- */
static async deleteAllEmpoignades() {
for (let actor of game.actors) {
let empList = actor.items.filter(it => it.type == "empoignade")
for (let emp of empList) {
await actor.deleteEmbeddedDocuments('Item', [emp.id])
}
}
}
/* -------------------------------------------- */
static async deleteLinkedEmpoignade(actorId, empoignade) {
let actorDeleteId = (actorId == empoignade.system.empoigneurid) ? empoignade.system.empoigneid : empoignade.system.empoigneurid
let actor = game.actors.get(actorDeleteId)
let emp = this.getEmpoignadeById(actor, empoignade.system.empoignadeid)
if (emp) {
await actor.deleteEmbeddedDocuments('Item', [emp._id])
}
}
/* -------------------------------------------- */
static async createEmpoignade(attacker, defender) {
return await Item.create({
name: "Empoignade en cours de " + attacker.name + ' sur ' + defender.name, type: 'empoignade',
img: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp",
system: { description: "", empoignadeid: randomID(16), compteempoigne: 0, empoigneurid: attacker.id, empoigneid: defender.id, ptsemp: 0, empoigneurname: attacker.name, empoignename: defender.name }
},
{
temporary: true
})
}
}

View File

@ -174,7 +174,7 @@ export class SystemReveDeDragon {
"recettealchimique", "musique", "chant", "danse", "jeu", "recettecuisine", "oeuvre", "recettealchimique", "musique", "chant", "danse", "jeu", "recettecuisine", "oeuvre",
"meditation", "queue", "ombre", "souffle", "tete", "casetmr", "sort", "sortreserve", "meditation", "queue", "ombre", "souffle", "tete", "casetmr", "sort", "sortreserve",
"nombreastral", "tache", "maladie", "poison", "possession", "nombreastral", "tache", "maladie", "poison", "possession",
"tarot", "extraitpoetique" "tarot", "extraitpoetique", "empoignade"
], makeDefault: true ], makeDefault: true
}); });
CONFIG.Combat.documentClass = RdDCombatManager; CONFIG.Combat.documentClass = RdDCombatManager;

View File

@ -15,6 +15,7 @@ import { RdDItemCompetence } from "./item-competence.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js"; import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js"; import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { RdDRaretes } from "./item/raretes.js"; import { RdDRaretes } from "./item/raretes.js";
import { RdDEmpoignade } from "./rdd-empoignade.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
// This table starts at 0 -> niveau -10 // This table starts at 0 -> niveau -10
@ -688,6 +689,44 @@ export class RdDUtility {
RdDPossession.onDefensePossession(attackerId, defenderId, possessionId) 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 // gestion bouton tchat Acheter
html.on("click", '.button-acheter', event => { html.on("click", '.button-acheter', event => {
const venteData = DialogItemAchat.preparerAchat(event.currentTarget); const venteData = DialogItemAchat.preparerAchat(event.currentTarget);

View File

@ -139,6 +139,12 @@ export const referenceAjustements = {
isUsed: (rollData, actor) => rollData.ethylisme != undefined, isUsed: (rollData, actor) => rollData.ethylisme != undefined,
getLabel: (rollData, actor) => "Ethylisme - " + RdDUtility.getNomEthylisme(rollData.ethylisme), getLabel: (rollData, actor) => "Ethylisme - " + RdDUtility.getNomEthylisme(rollData.ethylisme),
getValue: (rollData, actor) => rollData.ethylisme, getValue: (rollData, actor) => rollData.ethylisme,
},
tailleempoignade: {
isVisible: (rollData, actor) => rollData.isEmpoignade,
isUsed: (rollData, actor) => rollData.isEmpoignade,
getLabel: (rollData, actor) => "Malus de taille",
getValue: (rollData, actor) => rollData.malusTaille,
} }
} }

View File

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

View File

@ -538,7 +538,7 @@
"service", "service",
"meditation", "rencontre", "queue", "ombre", "souffle", "tete", "casetmr", "signedraconique", "sort", "sortreserve", "meditation", "rencontre", "queue", "ombre", "souffle", "tete", "casetmr", "signedraconique", "sort", "sortreserve",
"nombreastral", "tache", "blessure", "maladie", "poison", "possession", "nombreastral", "tache", "blessure", "maladie", "poison", "possession",
"tarot", "extraitpoetique" "tarot", "extraitpoetique", "empoignade"
], ],
"templates": { "templates": {
"description": { "description": {
@ -596,6 +596,16 @@
"ispossession": false, "ispossession": false,
"dommages": 0 "dommages": 0
}, },
"empoignade": {
"templates": ["description"],
"empoignadeid": "",
"empoigneurid": "",
"empoigneid": "",
"pointsemp": 0,
"empoigneurname": "",
"empoignename": "",
"ausol": false
},
"possession": { "possession": {
"templates": ["description"], "templates": ["description"],
"typepossession": "", "typepossession": "",

View File

@ -40,4 +40,29 @@
<span class="initiative-value"></span> <span class="initiative-value"></span>
</li> </li>
{{/each}} {{/each}}
</ul>
<ul class="item-list alterne-list">
<li class="competence-header flexrow">
<span class="competence-title competence-label">Empoignades</span>
<span class="competence-title competence-value">Points d'Emp</span>
</li>
{{#each empoignades as |emp key|}}
<li class="item flexrow list-item"
data-item-id="{{emp._id}}" data-arme-name="{{emp.name}}">
<span class="empoignade-label">
<a>
{{#if emp.img}}
<img class="sheet-competence-img" src="{{emp.img}}"/>
{{/if}}
<span>{{emp.name}}</span>
</a>
</span>
<span class="competence-value">{{emp.system.pointsemp}}</span>
<div class="item-controls">
<a class="item-edit" title="Edit Item"><i class="fas fa-edit"></i></a>
<a class="item-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
</div>
</li>
{{/each}}
</ul> </ul>

View File

@ -0,0 +1,39 @@
<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

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

View File

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

View File

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

View File

@ -0,0 +1,85 @@
<img class="chat-icon" src="{{competence.img}}" />
<h4>
{{#if (eq mode "empoigner")}}
{{attackerName}} tente d'empoigner {{defenderName}}
{{/if}}
{{#if (eq mode "contrer-empoigner")}}
{{defenderName}} tente de contrer l'empoignade de {{attackerName}}
{{/if}}
{{#if (eq mode "liberer")}}
{{attackerName}} tente de se libérer de l'empoignade de {{defenderName}}
{{/if}}
{{#if (eq mode "contrer-liberer")}}
{{defenderName}} tente de contrer la libération de {{attackerName}}
{{/if}}
</h4>
{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.html"}}
<hr>
<div>
{{#if (gte empoignade.system.pointsemp 2)}}
<br><strong>{{defenderName}} est empoigné et immobilisé par {{attackerName}} !</strong>
{{else}}
<span class='chat-card-button-area'>
<br>
{{#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)
</a>
{{/if}}
{{else}}
La Tentative d'empoignade a échoué !
{{/if}}
{{/if}}
{{#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)
</a>
{{else}}
La Tentative de libération a échouée !
{{/if}}
{{/if}}
{{#if (eq mode "contrer-empoigner")}}
{{#if rolled.isSuccess}}
La tentative de contrer l'empoignade est un succès!
{{else}}
La tentative de contrer l'empoignade est un échec!
{{/if}}
{{/if}}
{{#if (eq mode "contrer-liberer")}}
{{#if rolled.isSuccess}}
La tentative de contrer la libération est un succès!
{{else}}
La tentative de contrer la libération est un échec!
{{/if}}
{{/if}}
<br>Points d'Emp: {{empoignade.system.pointsemp}}
{{/if}}
</div>

View File

@ -0,0 +1,20 @@
<img class="chat-icon" src="{{competence.img}}" />
<h4>
{{attackerName}} tente d'empoigner {{defenderName}}
</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}}
a automatiquement l'initiative sur {{attacker.name}}, et bénéficie d'un bonus de +4 à son attaque. Assurez vous
d'avoir effectué cette attaque avant de poursuivre l'empoignade. Ce cas s'applique également si {{defender.name}}
combat à mains nues.</strong>
<a class='empoignade-poursuivre chat-card-button' data-attackerId='{{attacker.id}}'
data-defenderId='{{defender.id}}'>
Poursuivre l'empoignade
</a>
</div>

View File

@ -0,0 +1,22 @@
<form class="skill-roll-dialog">
<h2>
{{defenderName}} tente de contrer l'empoignade de {{attackerName}}
</h2>
<div class="grid grid-2col">
<div class="flex-group-left">
<img class="chat-icon" src="{{competence.img}}" alt="{{competence.name}}"/>
<div class="grid grid-2col">
<label for="carac">{{selectedCarac.label}}:</label><label class="flex-grow" name="carac">{{selectedCarac.value}}</label>
<label for="competence">{{competence.name}}:</label><label class="flex-grow" name="competence">{{numberFormat competence.system.niveau decimals=0 sign=true}}</label>
</div>
</div>
<div class="flex-group-left">
{{>"systems/foundryvtt-reve-de-dragon/templates/partial-roll-diffFixe.html"}}
{{>"systems/foundryvtt-reve-de-dragon/templates/partial-roll-diffCondition.html"}}
{{>"systems/foundryvtt-reve-de-dragon/templates/partial-roll-forcer.html"}}
<div class="placeholder-ajustements" class="flexrow"></div>
</div>
</div>
<div class="placeholder-resolution"></div>
</form>

View File

@ -0,0 +1,11 @@
<form class="{{cssClass}}" autocomplete="off">
{{>"systems/foundryvtt-reve-de-dragon/templates/header-item.html"}}
{{!-- Sheet Body --}}
<section class="sheet-body">
<div class="form-group">
<label for="xp">Points d'Empoignade </label>
<input class="attribute-value" type="text" name="system.pointsemp" value="{{system.pointsemp}}" data-dtype="Number"/>
</div>
{{>"systems/foundryvtt-reve-de-dragon/templates/partial-item-description.html"}}
</section>
</form>