Combat séparé par actions
la classe RdDCombat a pour vocation de gérer les interactions entre attaques, défenses, ... Séparation de: - attaque - parades - esquive - encaisser gestion des résultats de dés par actions - _onAttaqueParticuliere - _onAttaqueNormale - _onAttaqueEchec - _onAttaqueEchecTotal - _onParadeParticuliere - _onParadeNormale - _onParadeEchec - _onParadeEchecTotal - _onEsquiveParticuliere - _onEsquiveNormale - _onEsquiveEchec - _onEsquiveEchecTotal Séparation de demiSurprise et de needSignificative les callbacks des boutons dans le chat sont enregistrés cette classe Par ailleurs: - Fix mortel/non-mortel (coche puis décoche restait non-mortel) - création de classes pour les armes, les compétences - fix du recul (ne pouvait pas marcher)
This commit is contained in:
parent
59a54b8a90
commit
2bcc1a7ba3
220
module/actor.js
220
module/actor.js
@ -18,6 +18,8 @@ import { ChatUtility } from "./chat-utility.js";
|
|||||||
import { RdDItemSort } from "./item-sort.js";
|
import { RdDItemSort } from "./item-sort.js";
|
||||||
import { Grammar } from "./grammar.js";
|
import { Grammar } from "./grammar.js";
|
||||||
import { RdDCalendrier } from "./rdd-calendrier.js";
|
import { RdDCalendrier } from "./rdd-calendrier.js";
|
||||||
|
import { RdDItemArme } from "./item-arme.js";
|
||||||
|
import { RdDCombat } from "./rdd-combat.js";
|
||||||
|
|
||||||
export class RdDActor extends Actor {
|
export class RdDActor extends Actor {
|
||||||
|
|
||||||
@ -105,6 +107,10 @@ export class RdDActor extends Actor {
|
|||||||
this.computeEtatGeneral();
|
this.computeEtatGeneral();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
isCreature() {
|
||||||
|
return this.data.type == 'creature' || this.data.type == 'entite';
|
||||||
|
}
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
getReveActuel() {
|
getReveActuel() {
|
||||||
return this.data.data.reve.reve.value;
|
return this.data.data.reve.reve.value;
|
||||||
@ -114,6 +120,14 @@ export class RdDActor extends Actor {
|
|||||||
return this.data.data.compteurs.chance.value;
|
return this.data.data.compteurs.chance.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getForceValue() {
|
||||||
|
return this.data.data.carac.force ? this.data.data.carac.force.value : this.data.data.carac.reve.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
getCompetence(compName) {
|
||||||
|
return RdDUtility.findCompetence(this.data.items, compName);
|
||||||
|
}
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
getBestDraconic() {
|
getBestDraconic() {
|
||||||
const list = this.getDraconicList().sort((a, b) => b.data.niveau - a.data.niveau);
|
const list = this.getDraconicList().sort((a, b) => b.data.niveau - a.data.niveau);
|
||||||
@ -142,6 +156,24 @@ export class RdDActor extends Actor {
|
|||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
async performRoll(rollData, attacker = undefined) {
|
async performRoll(rollData, attacker = undefined) {
|
||||||
|
rollData.demiSurprise = this.isDemiSurprise();
|
||||||
|
|
||||||
|
// Manage weapon categories when parrying (cf. page 115 )
|
||||||
|
if (rollData.arme && rollData.attackerRoll) { // Manage parade depending on weapon type, and change roll results
|
||||||
|
let attCategory = RdDItemArme.getCategorieArme(rollData.attackerRoll.arme);
|
||||||
|
let defCategory = RdDItemArme.getCategorieArme(rollData.arme);
|
||||||
|
if (defCategory == "bouclier")
|
||||||
|
rollData.needSignificative = false;
|
||||||
|
else if (attCategory != defCategory)
|
||||||
|
rollData.needSignificative = true;
|
||||||
|
// Do we need to make resistance roll for defender ?
|
||||||
|
if (attCategory.match("epee") && (defCategory == "hache" || defCategory == "lance"))
|
||||||
|
rollData.needResist = true;
|
||||||
|
}
|
||||||
|
if (!this.isEntiteCauchemar() && rollData.particuliereAttaque == "finesse") {
|
||||||
|
rollData.needSignificative = true;
|
||||||
|
}
|
||||||
|
|
||||||
// garder le résultat
|
// garder le résultat
|
||||||
await RdDResolutionTable.rollData(rollData);
|
await RdDResolutionTable.rollData(rollData);
|
||||||
|
|
||||||
@ -152,11 +184,11 @@ export class RdDActor extends Actor {
|
|||||||
|
|
||||||
if (rollData.rolled.isPart && rollData.arme && !rollData.attackerRoll) { // Réussite particulière avec attaque -> choix !
|
if (rollData.rolled.isPart && rollData.arme && !rollData.attackerRoll) { // Réussite particulière avec attaque -> choix !
|
||||||
let message = "<strong>Réussite particulière en attaque</strong>";
|
let message = "<strong>Réussite particulière en attaque</strong>";
|
||||||
message = message + "<br><a class='chat-card-button' id='particuliere-attaque' data-mode='force' data-attackerid='" + this.data._id + "'>Attaquer en Force</a>";
|
message = message + "<br><a class='chat-card-button' id='particuliere-attaque' data-mode='force' data-attackerId='" + this.data._id + "'>Attaquer en Force</a>";
|
||||||
// Finesse et Rapidité seulement en mêlée et si la difficulté libre est de -1 minimum
|
// Finesse et Rapidité seulement en mêlée et si la difficulté libre est de -1 minimum
|
||||||
if (rollData.selectedCarac.label == "Mêlée" && rollData.diffLibre < 0 ) {
|
if (rollData.selectedCarac.label == "Mêlée" && rollData.diffLibre < 0 ) {
|
||||||
message = message + "<br><a class='chat-card-button' id='particuliere-attaque' data-mode='rapidite' data-attackerid='"+ this.data._id + "'>Attaquer en Rapidité</a>";
|
message = message + "<br><a class='chat-card-button' id='particuliere-attaque' data-mode='rapidite' data-attackerId='"+ this.data._id + "'>Attaquer en Rapidité</a>";
|
||||||
message = message + "<br><a class='chat-card-button' id='particuliere-attaque' data-mode='finesse' data-attackerid='"+ this.data._id + "'>Attaquer en Finesse</a>";
|
message = message + "<br><a class='chat-card-button' id='particuliere-attaque' data-mode='finesse' data-attackerId='"+ this.data._id + "'>Attaquer en Finesse</a>";
|
||||||
}
|
}
|
||||||
ChatMessage.create( {content : message, whisper: ChatMessage.getWhisperRecipients( this.name ) } );
|
ChatMessage.create( {content : message, whisper: ChatMessage.getWhisperRecipients( this.name ) } );
|
||||||
} else {
|
} else {
|
||||||
@ -201,23 +233,23 @@ export class RdDActor extends Actor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
computeRecul( rollData, encaisser = undefined ) { // Calcul du recul (p. 132)
|
async computeRecul( rollData, encaisser = undefined ) { // Calcul du recul (p. 132)
|
||||||
if ( rollData.arme || encaisser ) {
|
if ( rollData.arme || encaisser ) {
|
||||||
if ( (rollData.attackerRoll.particuliereAttaque && rollData.attackerRoll.particuliereAttaque == 'force') || rollData.attackerRoll.isCharge) {
|
if ( (rollData.attackerRoll.particuliereAttaque && rollData.attackerRoll.particuliereAttaque == 'force') || rollData.attackerRoll.isCharge) {
|
||||||
let reculNiveau = this.data.data.taille.value - (rollData.attackerRoll.forceValue+rollData.attackerRoll.arme.dommages);
|
let reculNiveau = Misc.toInt(this.data.data.carac.taille.value) - (rollData.attackerRoll.forceValue+rollData.attackerRoll.arme.data.dommagesReels);
|
||||||
let recul = RdDResolutionTable.roll( 10, reculNiveau );
|
let recul = await RdDResolutionTable.roll( 10, reculNiveau );
|
||||||
let msg = "";
|
let msg = "";
|
||||||
if (recul.isSuccess) {
|
if (recul.isSuccess) {
|
||||||
msg = "Jet de Recul réussit, aucun effet !";
|
msg = "Jet de Recul réussi, aucun effet !";
|
||||||
} else {
|
} else {
|
||||||
let chute = RdDResolutionTable.roll( this.data.data.carac.agilite.value, reculNiveau );
|
let chute = await RdDResolutionTable.roll( this.data.data.carac.agilite.value, reculNiveau );
|
||||||
if ( !chute.isSuccess || recul.isETotal ) {
|
if ( !chute.isSuccess || recul.isETotal ) {
|
||||||
msg = "Jet de Recul : Vous subissez le recul du coup, et vous chutez au sol ! Vous ne pouvez plus attaquer ce round.";
|
msg = "Jet de Recul : Vous subissez le recul du coup, et vous chutez au sol ! Vous ne pouvez plus attaquer ce round.";
|
||||||
} else {
|
} else {
|
||||||
msg = "Jet de Recul : Vous subissez le recul du coup, et vous reculez de quelques mètres ! Vous ne pouvez plus attaquer ce round.";
|
msg = "Jet de Recul : Vous subissez le recul du coup, et vous reculez de quelques mètres ! Vous ne pouvez plus attaquer ce round.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ChatMessage( {content: msg,
|
ChatMessage.create( {content: msg,
|
||||||
user: game.user._id,
|
user: game.user._id,
|
||||||
whisper: [game.user._id, ChatMessage.getWhisperRecipients("GM") ] } );
|
whisper: [game.user._id, ChatMessage.getWhisperRecipients("GM") ] } );
|
||||||
}
|
}
|
||||||
@ -229,22 +261,6 @@ export class RdDActor extends Actor {
|
|||||||
let rolled = rollData.rolled;
|
let rolled = rollData.rolled;
|
||||||
let quality = rolled.quality
|
let quality = rolled.quality
|
||||||
|
|
||||||
// Manage weapon categories when parrying (cf. page 115 )
|
|
||||||
let need_resist = false; // Do we need to make resistance roll for defender ?
|
|
||||||
if (rollData.arme && rollData.attackerRoll) { // Manage parade depending on weapon type, and change roll results
|
|
||||||
let attCategory = RdDUtility.getArmeCategory(rollData.attackerRoll.arme);
|
|
||||||
let defCategory = RdDUtility.getArmeCategory(rollData.arme);
|
|
||||||
if (defCategory == "bouclier")
|
|
||||||
rollData.needSignificative = false;
|
|
||||||
else if (attCategory != defCategory)
|
|
||||||
rollData.needSignificative = true;
|
|
||||||
if (attCategory.match("epee") && (defCategory == "hache" || defCategory == "lance"))
|
|
||||||
need_resist = true;
|
|
||||||
}
|
|
||||||
if (!this.isEntiteCauchemar() && (this.data.data.sante.sonne.value || rollData.particuliereAttaque == "finesse")) {
|
|
||||||
rollData.needSignificative = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(">>> ROLL", rollData, rolled);
|
console.log(">>> ROLL", rollData, rolled);
|
||||||
let xpmsg = RdDResolutionTable.buildXpMessage(rolled, rollData.finalLevel);
|
let xpmsg = RdDResolutionTable.buildXpMessage(rolled, rollData.finalLevel);
|
||||||
|
|
||||||
@ -267,7 +283,7 @@ export class RdDActor extends Actor {
|
|||||||
explications += " Significative nécessaire!";
|
explications += " Significative nécessaire!";
|
||||||
}
|
}
|
||||||
encaisser = rollData.needSignificative ? !rolled.isSign : !rolled.isSuccess;
|
encaisser = rollData.needSignificative ? !rolled.isSign : !rolled.isSuccess;
|
||||||
this.computeRecul( rollData, encaisser );
|
await this.computeRecul( rollData, encaisser );
|
||||||
} else { // This is the attack roll!
|
} else { // This is the attack roll!
|
||||||
if (rolled.isSuccess) {
|
if (rolled.isSuccess) {
|
||||||
let target = this._getTarget();
|
let target = this._getTarget();
|
||||||
@ -280,8 +296,8 @@ export class RdDActor extends Actor {
|
|||||||
ChatMessage.create( { content: "Vous avez attaqué en Rapidité. Ce cas n'est pas géré autmatiquement, donc suivez les directives de votre MJ pour gérer ce cas.",
|
ChatMessage.create( { content: "Vous avez attaqué en Rapidité. Ce cas n'est pas géré autmatiquement, donc suivez les directives de votre MJ pour gérer ce cas.",
|
||||||
whisper: ChatMessage.getWhisperRecipients( this.name ) } );
|
whisper: ChatMessage.getWhisperRecipients( this.name ) } );
|
||||||
}
|
}
|
||||||
rollData.domArmePlusDom = this._calculBonusDommages(rollData.selectedCarac, rollData.arme, rollData.particuliereAttaque == 'force' );
|
rollData.domArmePlusDom = this._calculBonusDegats(rollData);
|
||||||
rollData.degats = new Roll("2d10").roll().total + rollData.domArmePlusDom + ((rollData.isCharge)?2:0); // Dégats totaux
|
rollData.degats = new Roll("2d10").roll().total + rollData.domArmePlusDom; // Dégats totaux
|
||||||
rollData.loc = RdDUtility.getLocalisation();
|
rollData.loc = RdDUtility.getLocalisation();
|
||||||
|
|
||||||
if (target)
|
if (target)
|
||||||
@ -334,6 +350,25 @@ export class RdDActor extends Actor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getSurprise() {
|
||||||
|
if (this.isEntiteCauchemar()) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
// TODO: gestion des conditions de demi-surprise
|
||||||
|
if ( this.data.data.sante.sonne.value) {
|
||||||
|
return 'demi';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
isDemiSurprise() {
|
||||||
|
return this.getSurprise() == 'demi';
|
||||||
|
}
|
||||||
|
|
||||||
|
isSurpriseTotale() {
|
||||||
|
return this.getSurprise() == 'totale';
|
||||||
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static _calculMortaliteEncaissement(rollData, target) {
|
static _calculMortaliteEncaissement(rollData, target) {
|
||||||
const mortalite = target.actor.isEntiteCauchemar() ? "cauchemar" : (rollData.mortalite ? rollData.mortalite : "mortel");
|
const mortalite = target.actor.isEntiteCauchemar() ? "cauchemar" : (rollData.mortalite ? rollData.mortalite : "mortel");
|
||||||
@ -342,20 +377,23 @@ export class RdDActor extends Actor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
_calculBonusDommages(carac, arme, isForce=false) {
|
_calculBonusDegats(rollData) {
|
||||||
if ( arme.name.toLowerCase() == "esquive") return 0; // Specific case management
|
if ( rollData.arme.name.toLowerCase() == "esquive") return 0; // Specific case management
|
||||||
let dmgArme = 0;
|
|
||||||
|
const dmgConditions = rollData.isCharge ? 2 : 0;
|
||||||
|
const dmgParticuliere = rollData.particuliereAttaque == 'force' ? 5 : 0;
|
||||||
|
const dmgArme = parseInt(rollData.arme.data.dommages);
|
||||||
|
const dmgPerso = this._calculBonusDegatsActor(rollData.selectedCarac.label, dmgArme);
|
||||||
|
return dmgArme + dmgPerso + dmgConditions + dmgParticuliere;
|
||||||
|
}
|
||||||
|
|
||||||
|
_calculBonusDegatsActor(caracName, dmgArme) {
|
||||||
const dmgPerso = parseInt(this.data.data.attributs.plusdom.value);
|
const dmgPerso = parseInt(this.data.data.attributs.plusdom.value);
|
||||||
if ( arme.data.dommages ) {
|
switch (caracName) {
|
||||||
dmgArme = parseInt(arme.data.dommages) + (isForce)? 5 : 0;
|
case "Tir": return 0;
|
||||||
if (carac.label == "Tir") {
|
case "Lancer": return Math.max(0, Math.min(dmgArme, dmgPerso));
|
||||||
return dmgArme;
|
|
||||||
}
|
|
||||||
if (carac.label == "Lancer") {
|
|
||||||
return dmgArme + Math.min(dmgArme, dmgPerso);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return dmgArme + dmgPerso;
|
return dmgPerso;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@ -639,7 +677,7 @@ export class RdDActor extends Actor {
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
async updateCreatureCompetence( compName, fieldName, compValue )
|
async updateCreatureCompetence( compName, fieldName, compValue )
|
||||||
{
|
{
|
||||||
let comp = RdDUtility.findCompetence( this.data.items, compName);
|
let comp = this.getCompetence(compName);
|
||||||
console.log( comp );
|
console.log( comp );
|
||||||
if ( comp ) {
|
if ( comp ) {
|
||||||
const update = {_id: comp._id }
|
const update = {_id: comp._id }
|
||||||
@ -657,7 +695,7 @@ export class RdDActor extends Actor {
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
async updateCompetence( compName, compValue )
|
async updateCompetence( compName, compValue )
|
||||||
{
|
{
|
||||||
let comp = RdDUtility.findCompetence( this.data.items, compName);
|
let comp = this.getCompetence(compName);
|
||||||
if ( comp ) {
|
if ( comp ) {
|
||||||
let troncList = RdDUtility.isTronc( compName );
|
let troncList = RdDUtility.isTronc( compName );
|
||||||
let maxNiveau = compValue;
|
let maxNiveau = compValue;
|
||||||
@ -679,7 +717,7 @@ export class RdDActor extends Actor {
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
async updateCompetenceXP( compName, compValue )
|
async updateCompetenceXP( compName, compValue )
|
||||||
{
|
{
|
||||||
let comp = RdDUtility.findCompetence( this.data.items, compName);
|
let comp = this.getCompetence(compName);
|
||||||
if ( comp ) {
|
if ( comp ) {
|
||||||
const update = {_id: comp._id, 'data.xp': compValue };
|
const update = {_id: comp._id, 'data.xp': compValue };
|
||||||
const updated = await this.updateEmbeddedEntity("OwnedItem", update); // Updates one EmbeddedEntity
|
const updated = await this.updateEmbeddedEntity("OwnedItem", update); // Updates one EmbeddedEntity
|
||||||
@ -1251,7 +1289,7 @@ export class RdDActor extends Actor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
_createCallbackExperience() {
|
createCallbackExperience() {
|
||||||
return {
|
return {
|
||||||
condition: r => r.rolled.isPart && r.finalLevel < 0 && game.settings.get("core", "rollMode") != 'selfroll',
|
condition: r => r.rolled.isPart && r.finalLevel < 0 && game.settings.get("core", "rollMode") != 'selfroll',
|
||||||
action: r => this._appliquerAjoutExperience(r)
|
action: r => this._appliquerAjoutExperience(r)
|
||||||
@ -1296,7 +1334,7 @@ export class RdDActor extends Actor {
|
|||||||
name: 'lancer-un-sort',
|
name: 'lancer-un-sort',
|
||||||
label: 'Lancer un sort',
|
label: 'Lancer un sort',
|
||||||
callbacks: [
|
callbacks: [
|
||||||
this._createCallbackExperience(),
|
this.createCallbackExperience(),
|
||||||
{ action: r => this._rollUnSortResult(r, false) }
|
{ action: r => this._rollUnSortResult(r, false) }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -1304,7 +1342,7 @@ export class RdDActor extends Actor {
|
|||||||
name: 'mettre-en-reserve',
|
name: 'mettre-en-reserve',
|
||||||
label: 'Mettre un sort en réserve',
|
label: 'Mettre un sort en réserve',
|
||||||
callbacks: [
|
callbacks: [
|
||||||
this._createCallbackExperience(),
|
this.createCallbackExperience(),
|
||||||
{ action: r => this._rollUnSortResult(r, true) }
|
{ action: r => this._rollUnSortResult(r, true) }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -1405,7 +1443,7 @@ export class RdDActor extends Actor {
|
|||||||
name: 'jet-'+caracName,
|
name: 'jet-'+caracName,
|
||||||
label: 'Jet ' + Grammar.apostrophe('de', rollData.selectedCarac.label),
|
label: 'Jet ' + Grammar.apostrophe('de', rollData.selectedCarac.label),
|
||||||
callbacks: [
|
callbacks: [
|
||||||
this._createCallbackExperience(),
|
this.createCallbackExperience(),
|
||||||
{ action: this._rollCaracResult }
|
{ action: this._rollCaracResult }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -1434,25 +1472,25 @@ export class RdDActor extends Actor {
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
async rollCompetence( name ) {
|
async rollCompetence( name ) {
|
||||||
let rollData = {
|
let rollData = {
|
||||||
competence: duplicate(RdDUtility.findCompetence( this.data.items, name)),
|
competence: duplicate(this.getCompetence(name)),
|
||||||
needSignificative : !this.isEntiteCauchemar() && this.data.data.sante.sonne.value
|
needSignificative : !this.isEntiteCauchemar() && this.data.data.sante.sonne.value
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rollData.competence.type == 'competencecreature') {
|
if (rollData.competence.type == 'competencecreature') {
|
||||||
// Fake competence pour créature
|
// Fake competence pour créature
|
||||||
mergeObject(rollData.competence, { data : { defaut_carac: "carac_creature", categorie: "creature" } });
|
rollData.competence.data = { defaut_carac: "carac_creature", categorie: "creature" };
|
||||||
rollData.carac = { carac_creature: { label: competence.name, value: competence.data.carac_value } };
|
rollData.carac = { carac_creature: { label: competence.name, value: competence.data.carac_value } };
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
rollData.carac = this.data.data.carac;
|
rollData.carac = this.data.data.carac;
|
||||||
}
|
}
|
||||||
console.log("rollCompetence !!!", rollData.competence);
|
console.log("rollCompetence !!!", rollData);
|
||||||
|
|
||||||
const dialog = await RdDRoll.create(this, rollData, {html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-competence.html'}, {
|
const dialog = await RdDRoll.create(this, rollData, {html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-competence.html'}, {
|
||||||
name: 'jet-competence',
|
name: 'jet-competence',
|
||||||
label: 'Jet ' +Grammar.apostrophe('de', name),
|
label: 'Jet ' +Grammar.apostrophe('de', name),
|
||||||
callbacks: [
|
callbacks: [
|
||||||
this._createCallbackExperience(),
|
this.createCallbackExperience(),
|
||||||
{ action: this._competenceResult }
|
{ action: this._competenceResult }
|
||||||
]
|
]
|
||||||
} );
|
} );
|
||||||
@ -1480,7 +1518,7 @@ export class RdDActor extends Actor {
|
|||||||
name: 'appelChance',
|
name: 'appelChance',
|
||||||
label: 'Appel à la chance',
|
label: 'Appel à la chance',
|
||||||
callbacks: [
|
callbacks: [
|
||||||
this._createCallbackExperience(),
|
this.createCallbackExperience(),
|
||||||
{ action: r => this._appelChanceResult(r) }
|
{ action: r => this._appelChanceResult(r) }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -1516,21 +1554,24 @@ export class RdDActor extends Actor {
|
|||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
appliquerExperience( rolled, caracName, competenceName = undefined ) {
|
appliquerExperience( rolled, caracName, competenceName = undefined ) {
|
||||||
// TODO gestion derobe/tir/lance/melee
|
// TODO: en cas de désir lancinant, pas d'expérience sur particulière
|
||||||
if (caracName == 'derobee') caracName = 'agilite';
|
|
||||||
|
|
||||||
if ( rolled.isPart && rolled.finalLevel < 0) {
|
if ( rolled.isPart && rolled.finalLevel < 0) {
|
||||||
if ( !compentenceName) {
|
|
||||||
this.actor.data.data.carac[caracName].xp += 1;
|
if (caracName == 'derobee') caracName = 'agilite';
|
||||||
|
|
||||||
|
let xp = Math.abs(rolled.finalLevel);
|
||||||
|
let xpCarac = Math.floor(xp / 2); // impair: arrondi inférieur en carac
|
||||||
|
|
||||||
|
if ( !competenceName) {
|
||||||
|
this.actor.data.data.carac[caracName].xp += Math.max(xpCarac, 1);
|
||||||
} else {
|
} else {
|
||||||
let competence = RdDUtility.findCompetence( this.data.items, competenceName );
|
let competence = RdDUtility.findCompetence( this.data.items, competenceName );
|
||||||
let xpCarac = Math.floor(Math.abs(rolled.finalLevel) / 2);
|
let xpComp = xp - xpCarac;
|
||||||
if ( xpCarac == 0 ) {
|
|
||||||
competence.data.xp += 1; // XP en priorité à la compétencence
|
competence.data.xp += xpComp;
|
||||||
} else
|
|
||||||
competence.data.xp += Math.ceil(Math.abs(rolled.finalLevel) / 2); // XP majoritaire en compentece (ie cas impair)
|
|
||||||
this.actor.data.data.carac[caracName].xp += xpCarac;
|
this.actor.data.data.carac[caracName].xp += xpCarac;
|
||||||
}
|
}
|
||||||
|
// TODO: save actor?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1630,10 +1671,8 @@ export class RdDActor extends Actor {
|
|||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
async rollCompetenceCreature( compName ) {
|
async rollCompetenceCreature( compName ) {
|
||||||
let competence = RdDUtility.findCompetence( this.data.items, compName);
|
let competence = this.getCompetence(compName);
|
||||||
|
|
||||||
if ( competence.type == 'competencecreature' && competence.data.iscombat ) {
|
if ( competence.type == 'competencecreature' && competence.data.iscombat ) {
|
||||||
armeItem = { name: compName, data: { dommages: competence.data.dommages, dommagesReels: competence.data.dommages} };
|
|
||||||
this.rollCompetenceCombat(competence, armeItem);
|
this.rollCompetenceCombat(competence, armeItem);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -1642,27 +1681,31 @@ export class RdDActor extends Actor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
rollArme(competenceName, armeName) {
|
rollArme(compName, armeName = undefined) {
|
||||||
|
|
||||||
let armeItem = this.data.items.find(item=>item.type==="arme" && (item.name === armeName));
|
let armeItem = this.data.items.find(item=>item.type==="arme" && (item.name === armeName));
|
||||||
if (armeItem && competenceName == undefined) competenceName = armeItem.data.competence;
|
if (armeItem && compName == undefined) compName = armeItem.data.competence;
|
||||||
let competence = RdDUtility.findCompetence(this.data.items, competenceName == undefined? armeName : competenceName);
|
let competence = this.getCompetence(compName == undefined? armeName : compName);
|
||||||
|
|
||||||
if (armeItem==undefined && competence.type == 'competencecreature' && competence.data.iscombat ) {
|
if (armeItem || armeName || (competence.type == 'competencecreature' && competence.data.iscombat)) {
|
||||||
armeItem = { name: name, data: { dommages: competence.data.dommages, dommagesReels: competence.data.dommages} };
|
this.rollCompetenceCombat( compName, armeItem );
|
||||||
}
|
|
||||||
|
|
||||||
if (armeItem || armeName) {
|
|
||||||
this.rollCompetenceCombat( competenceName, armeItem );
|
|
||||||
} else {
|
} else {
|
||||||
this.rollCompetence( competence.name );
|
this.rollCompetence( competence.name );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
async rollCompetenceCombat( name, armeItem=undefined, attackerRoll=undefined, attacker = undefined) {
|
async rollCompetenceCombat( compName, armeItem=undefined, attackerRoll=undefined, attacker = undefined) {
|
||||||
let competence = RdDUtility.findCompetence( this.data.items, name);
|
let competence = this.getCompetence(compName);
|
||||||
|
|
||||||
|
if (RdDCombat.isActive()) {
|
||||||
|
const assaut = RdDCombat.createUsingTarget(this);
|
||||||
|
assaut.attaque(competence, armeItem);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ( competence.type == 'competencecreature' && competence.data.iscombat ) {
|
if ( competence.type == 'competencecreature' && competence.data.iscombat ) {
|
||||||
armeItem = { name: name, data: { dommages: competence.data.dommages, dommagesReels: competence.data.dommages} };
|
armeItem = { name: compName, data: { dommages: competence.data.dommages, dommagesReels: competence.data.dommages} };
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("rollCompetenceCombat !!!", competence, armeItem, attackerRoll);
|
console.log("rollCompetenceCombat !!!", competence, armeItem, attackerRoll);
|
||||||
@ -1672,7 +1715,7 @@ export class RdDActor extends Actor {
|
|||||||
difficultesLibres: CONFIG.RDD.difficultesLibres,
|
difficultesLibres: CONFIG.RDD.difficultesLibres,
|
||||||
etat: this.data.data.compteurs.etat.value,
|
etat: this.data.data.compteurs.etat.value,
|
||||||
diffConditions: 0,
|
diffConditions: 0,
|
||||||
forceValue : attackerRoll ? (this.data.data.carac.force ? this.data.data.carac.force.value : this.data.data.carac.reve.value) : 0, // Utilisé pour le jet de recul
|
forceValue : attackerRoll ? this.getForceValue() : 0, // Utilisé pour le jet de recul
|
||||||
diffLibre: (attackerRoll) ? attackerRoll.diffLibre : 0,
|
diffLibre: (attackerRoll) ? attackerRoll.diffLibre : 0,
|
||||||
attackerRoll: attackerRoll,
|
attackerRoll: attackerRoll,
|
||||||
finalLevel: 0,
|
finalLevel: 0,
|
||||||
@ -1690,7 +1733,7 @@ export class RdDActor extends Actor {
|
|||||||
rollData.surencMalusFlag = (this.data.data.compteurs.surenc.value < 0);
|
rollData.surencMalusFlag = (this.data.data.compteurs.surenc.value < 0);
|
||||||
rollData.surencMalusValue = this.data.data.compteurs.surenc.value;
|
rollData.surencMalusValue = this.data.data.compteurs.surenc.value;
|
||||||
rollData.surencMalusApply = false;
|
rollData.surencMalusApply = false;
|
||||||
rollData.isNatation = name.toLowerCase().includes("natation");
|
rollData.isNatation = compName.toLowerCase().includes("natation");
|
||||||
rollData.useEncForNatation = false;
|
rollData.useEncForNatation = false;
|
||||||
rollData.encValueForNatation = (this.encombrementTotal) ? Math.round(this.encombrementTotal) : 0;
|
rollData.encValueForNatation = (this.encombrementTotal) ? Math.round(this.encombrementTotal) : 0;
|
||||||
}
|
}
|
||||||
@ -1700,24 +1743,11 @@ export class RdDActor extends Actor {
|
|||||||
competence.data.categorie = "creature"; // Fake default competence
|
competence.data.categorie = "creature"; // Fake default competence
|
||||||
rollData.competence = competence;
|
rollData.competence = competence;
|
||||||
rollData.arme = armeItem;
|
rollData.arme = armeItem;
|
||||||
rollData.carac = { carac_creature: { label: name, value: competence.data.carac_value } };
|
rollData.carac = { carac_creature: { label: compName, value: competence.data.carac_value } };
|
||||||
} else { // Usual competence
|
} else { // Usual competence
|
||||||
rollData.competence = competence;
|
rollData.competence = competence;
|
||||||
if (armeItem ) {
|
if (armeItem) {
|
||||||
armeItem.data.dommagesReels = armeItem.data.dommages; // Per default
|
armeItem = RdDItemArme.armeUneOuDeuxMains(armeItem, compName.toLowerCase().includes("1 main"));
|
||||||
if ( !armeItem.data.unemain && !armeItem.data.deuxmains) // Force default
|
|
||||||
armeItem.data.unemain = true;
|
|
||||||
if (armeItem.data.unemain && armeItem.data.deuxmains) { // manage 1/2 main
|
|
||||||
//console.log("Weapon", armeItem.data.dommages);
|
|
||||||
if ( armeItem.data.dommages.includes("/") ) { // Sanity check
|
|
||||||
if ( name.toLowerCase().includes("1 main") )
|
|
||||||
armeItem.data.dommagesReels = Number(armeItem.data.dommages.split("/")[0]);
|
|
||||||
else // 2 mains
|
|
||||||
armeItem.data.dommagesReels = Number(armeItem.data.dommages.split("/")[1]);
|
|
||||||
} else {
|
|
||||||
ui.notifications.info("Les dommages de l'arme à 1/2 mains " + name + " ne sont pas corrects (ie sous la forme X/Y)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
rollData.arme = armeItem;
|
rollData.arme = armeItem;
|
||||||
rollData.carac = this.data.data.carac;
|
rollData.carac = this.data.data.carac;
|
||||||
|
71
module/item-arme.js
Normal file
71
module/item-arme.js
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
|
||||||
|
export class RdDItemArme extends Item {
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
static getCategorieArme(arme) {
|
||||||
|
if (arme.data.competence == undefined) {
|
||||||
|
return 'competencecreature';
|
||||||
|
}
|
||||||
|
let compname = arme.data.competence.toLowerCase();
|
||||||
|
|
||||||
|
if (compname.match("hache")) return "hache";
|
||||||
|
if (compname.match("hast")) return "hast";
|
||||||
|
if (compname.match("lance")) return "lance";
|
||||||
|
if (compname.match("bouclier")) return "bouclier";
|
||||||
|
if (compname.match("masse")) return "masse";
|
||||||
|
if (compname.match("fléau")) return "fleau";
|
||||||
|
if (compname.match("epée") || compname.match("épée")) {
|
||||||
|
let armename = arme.name.toLowerCase();
|
||||||
|
if (armename.match("gnome"))
|
||||||
|
return "epee_courte";
|
||||||
|
return "epee_longue";
|
||||||
|
}
|
||||||
|
if (compname.match("dague")) {
|
||||||
|
return "epee_courte";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
static needParadeSignificative(armeAttaque, armeParade) {
|
||||||
|
let attCategory = RdDItemArme.getCategorieArme(armeAttaque);
|
||||||
|
let defCategory = RdDItemArme.getCategorieArme(armeParade);
|
||||||
|
if (defCategory == "bouclier" || attCategory == defCategory) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let armeParadeName = armeParade.name.toLowerCase();
|
||||||
|
let armeAttaqueName = armeAttaque.name.toLowerCase();
|
||||||
|
if (armeParadeName.match("dague") && armeAttaqueName.match(/((e|é)pée dragone|esparlongue|demi-dragonne)/)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Manage weapon categories when parrying (cf. page 115 )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
static armeUneOuDeuxMains(arme, aUneMain) {
|
||||||
|
arme.data.unemain = arme.data.unemain || !arme.data.deuxmains;
|
||||||
|
const uneOuDeuxMains = arme.data.unemain && arme.data.deuxmains;
|
||||||
|
if (arme.data.dommages.includes("/")) { // Sanity check
|
||||||
|
arme = duplicate(arme);
|
||||||
|
|
||||||
|
const tableauDegats = arme.data.dommages.split("/");
|
||||||
|
if (aUneMain)
|
||||||
|
arme.data.dommagesReels = Number(tableauDegats[0]);
|
||||||
|
else // 2 mains
|
||||||
|
arme.data.dommagesReels = Number(tableauDegats[1]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
arme.data.dommagesReels = Number(arme.data.dommages);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
(uneOuDeuxMains && !arme.data.dommages.includes("/")) ||
|
||||||
|
(!uneOuDeuxMains && arme.data.dommages.includes("/")))
|
||||||
|
{
|
||||||
|
ui.notifications.info("Les dommages de l'arme à 1/2 mains " + arme.name + " ne sont pas corrects (ie sous la forme X/Y)");
|
||||||
|
}
|
||||||
|
return arme;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
11
module/item-competence.js
Normal file
11
module/item-competence.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
export class RdDItemCompetence extends Item {
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
static isCompetenceMelee(name) {
|
||||||
|
return name.toLowerCase().match(/(epée|épée|hache|fleau|fléau|masse|lance|hast|dague|bouclier)/);
|
||||||
|
}
|
||||||
|
static isArmeUneMain(competence) {
|
||||||
|
return competence.name.toLowerCase().includes("1 main");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
572
module/rdd-combat.js
Normal file
572
module/rdd-combat.js
Normal file
@ -0,0 +1,572 @@
|
|||||||
|
import { RdDActor } from "./actor.js";
|
||||||
|
import { ChatUtility } from "./chat-utility.js";
|
||||||
|
import { RdDItemArme } from "./item-arme.js";
|
||||||
|
import { RdDItemCompetence } from "./item-competence.js";
|
||||||
|
import { Misc } from "./misc.js";
|
||||||
|
import { RdDResolutionTable } from "./rdd-resolution-table.js";
|
||||||
|
import { RdDRoll } from "./rdd-roll.js";
|
||||||
|
import { RdDUtility } from "./rdd-utility.js";
|
||||||
|
|
||||||
|
export class RdDCombat {
|
||||||
|
|
||||||
|
static isActive() {
|
||||||
|
return game.settings.get("foundryvtt-reve-de-dragon", "moteur-combat") == 'experimental';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
static createUsingTarget(attacker) {
|
||||||
|
const target = RdDCombat.getTarget();
|
||||||
|
if (target == undefined) {
|
||||||
|
ui.notifications.warn("Vous devriez choisir une cible à attaquer!");
|
||||||
|
}
|
||||||
|
return this.create(attacker, target ? target.actor : undefined, target)
|
||||||
|
}
|
||||||
|
|
||||||
|
static getTarget() {
|
||||||
|
if (game.user.targets && game.user.targets.size == 1) {
|
||||||
|
for (let target of game.user.targets) {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
static create(attacker, defender, target = undefined) {
|
||||||
|
return new RdDCombat(attacker, defender, target)
|
||||||
|
}
|
||||||
|
|
||||||
|
static createForEvent(event) {
|
||||||
|
let attackerId = event.currentTarget.attributes['data-attackerId'].value;
|
||||||
|
let attacker = game.actors.get(attackerId);
|
||||||
|
|
||||||
|
const dataDefenderTokenId = event.currentTarget.attributes['data-defenderTokenId'];
|
||||||
|
if (dataDefenderTokenId) {
|
||||||
|
let defenderToken = canvas.tokens.get(dataDefenderTokenId.value);
|
||||||
|
let defender = defenderToken.actor;
|
||||||
|
|
||||||
|
return this.create(attacker, defender);
|
||||||
|
}
|
||||||
|
return this.createUsingTarget(attacker)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(attacker, defender, target) {
|
||||||
|
this.attacker = attacker;
|
||||||
|
this.defender = defender;
|
||||||
|
this.target = target;
|
||||||
|
this.attackerId = this.attacker.data._id;
|
||||||
|
this.defenderId = this.defender.data._id;
|
||||||
|
this.defenderTokenId = target ? target.data._id : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
static registerChatCallbacks(html) {
|
||||||
|
for (let button of ['#parer-button', '#esquiver-button', '#particuliere-attaque', '#encaisser-button']) {
|
||||||
|
html.on("click", button, event => {
|
||||||
|
event.preventDefault();
|
||||||
|
RdDCombat.createForEvent(event).onEvent(button, event);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
async onEvent(button, event) {
|
||||||
|
if (!RdDCombat.isActive()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let rollData = game.system.rdd.rollDataHandler[this.attackerId];
|
||||||
|
// TODO: enlever le ChatMessage?
|
||||||
|
switch (button) {
|
||||||
|
case '#particuliere-attaque': return await this.choixParticuliere(rollData, event.currentTarget.attributes['data-mode'].value);
|
||||||
|
case '#parer-button': return this.parade(rollData, event.currentTarget.attributes['data-armeid'].value);
|
||||||
|
case '#esquiver-button': return this.esquive(rollData);
|
||||||
|
case '#encaisser-button': return this.encaisser(rollData, event.currentTarget.attributes['data-defenderTokenId'].value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
async attaque(competence, arme) {
|
||||||
|
if (!await this.accorderEntite('avant-attaque')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let rollData = this._prepareAttaque(competence, arme);
|
||||||
|
console.log("RdDCombat.attaque >>>", rollData);
|
||||||
|
|
||||||
|
const dialog = await RdDRoll.create(this.attacker, rollData,
|
||||||
|
{ html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-competence.html' }, {
|
||||||
|
name: 'jet-attaque',
|
||||||
|
label: 'Attaque: ' + (arme ? arme.name : competence.name),
|
||||||
|
callbacks: [
|
||||||
|
this.attacker.createCallbackExperience(),
|
||||||
|
{ condition: RdDResolutionTable.isParticuliere, action: r => this._onAttaqueParticuliere(r) },
|
||||||
|
{ condition: r => (RdDResolutionTable.isReussite(r) && !RdDResolutionTable.isParticuliere(r)), action: r => this._onAttaqueNormale(r) },
|
||||||
|
{ condition: RdDResolutionTable.isEchecTotal, action: r => this._onAttaqueEchecTotal(r) },
|
||||||
|
{ condition: RdDResolutionTable.isEchec, action: r => this._onAttaqueEchec(r) }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
dialog.render(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
_prepareAttaque(competence, arme) {
|
||||||
|
let rollData = {
|
||||||
|
coupsNonMortels: false,
|
||||||
|
competence: competence,
|
||||||
|
demiSurprise: this.attacker.isDemiSurprise()
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.attacker.isCreature()) {
|
||||||
|
this._prepareRollDataCreature(rollData, competence);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Usual competence
|
||||||
|
rollData.arme = RdDItemArme.armeUneOuDeuxMains(arme, RdDItemCompetence.isArmeUneMain(competence));
|
||||||
|
}
|
||||||
|
return rollData;
|
||||||
|
}
|
||||||
|
|
||||||
|
_prepareRollDataCreature(rollData, competence) {
|
||||||
|
competence = duplicate(competence);
|
||||||
|
competence.data.defaut_carac = "carac_creature";
|
||||||
|
competence.data.categorie = "creature";
|
||||||
|
|
||||||
|
rollData.competence = competence;
|
||||||
|
rollData.carac = { "carac_creature": { label: competence.name, value: competence.data.carac_value } };
|
||||||
|
rollData.arme = {
|
||||||
|
name: competence.name, data: {
|
||||||
|
dommages: competence.data.dommages,
|
||||||
|
dommagesReels: competence.data.dommages
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
_onAttaqueParticuliere(rollData) {
|
||||||
|
console.log("RdDCombat.onAttaqueParticuliere >>>", rollData);
|
||||||
|
let message = "<strong>Réussite particulière en attaque</strong>";
|
||||||
|
message += "<br><a class='chat-card-button' id='particuliere-attaque' data-mode='force' data-attackerId='" + this.attackerId + "'>Attaquer en Force</a>";
|
||||||
|
// Finesse et Rapidité seulement en mêlée et si la difficulté libre est de -1 minimum
|
||||||
|
if (rollData.selectedCarac.label == "Mêlée" && rollData.diffLibre < 0) {
|
||||||
|
message += "<br><a class='chat-card-button' id='particuliere-attaque' data-mode='rapidite' data-attackerId='" + this.attackerId + "'>Attaquer en Rapidité</a>";
|
||||||
|
message += "<br><a class='chat-card-button' id='particuliere-attaque' data-mode='finesse' data-attackerId='" + this.attackerId + "'>Attaquer en Finesse</a>";
|
||||||
|
}
|
||||||
|
game.system.rdd.rollDataHandler[this.attackerId] = rollData;
|
||||||
|
// TODO: use a dialog?
|
||||||
|
ChatMessage.create({ content: message, whisper: ChatMessage.getWhisperRecipients(this.attacker.name) });
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
async _onAttaqueNormale(rollData) {
|
||||||
|
console.log("RdDCombat.onAttaqueNormale >>>", rollData);
|
||||||
|
if (!await this.accorderEntite('avant-defense')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let explications = "";
|
||||||
|
|
||||||
|
// Message spécial pour la rapidité, qui reste difficile à gérer automatiquement
|
||||||
|
if (rollData.particuliereAttaque == 'rapidite') {
|
||||||
|
ChatMessage.create({
|
||||||
|
content: "Vous avez attaqué en Rapidité. Vous pourrez faire une deuxième attaque, ou utiliser votre arme pour vous défendre.",
|
||||||
|
whisper: ChatMessage.getWhisperRecipients(this.attacker.name)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
rollData.domArmePlusDom = this.attacker._calculBonusDegats(rollData);
|
||||||
|
rollData.degats = new Roll("2d10").roll().total + rollData.domArmePlusDom; // Dégats totaux
|
||||||
|
rollData.loc = RdDUtility.getLocalisation();
|
||||||
|
|
||||||
|
if (this.target) {
|
||||||
|
rollData.mortalite = this._calculMortaliteEncaissement(rollData);
|
||||||
|
explications += "<br><strong>Cible</strong> : " + this.defender.data.name;
|
||||||
|
}
|
||||||
|
explications += "<br>Encaissement : " + rollData.degats + "<br>Localisation : " + rollData.loc.label;
|
||||||
|
|
||||||
|
// Save rollData for defender
|
||||||
|
game.system.rdd.rollDataHandler[this.attackerId] = duplicate(rollData);
|
||||||
|
|
||||||
|
// Final chat message
|
||||||
|
let chatOptions = {
|
||||||
|
content: "<strong>Test : " + rollData.selectedCarac.label + " / " + rollData.competence.name + "</strong>"
|
||||||
|
+ "<br>Difficultés <strong>libre : " + rollData.diffLibre + "</strong> / conditions : " + Misc.toSignedString(rollData.diffConditions) + " / état : " + rollData.etat
|
||||||
|
+ RdDResolutionTable.explain(rollData.rolled)
|
||||||
|
+ explications
|
||||||
|
}
|
||||||
|
ChatUtility.chatWithRollMode(chatOptions, this.attacker.name)
|
||||||
|
if (this.target) {
|
||||||
|
this._messageDefenseur(rollData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
_messageDefenseur(rollData) {
|
||||||
|
console.log("RdDCombat._messageDefenseur", rollData, " / ", this.attacker, this.target, this.target.actor.isToken, this.attacker.data._id, rollData.competence.data.categorie);
|
||||||
|
|
||||||
|
let content = "<strong>" + this.defender.name + "</strong> doit se défendre : <br><span class='chat-card-button-area'>";
|
||||||
|
|
||||||
|
// parades
|
||||||
|
let filterArmesParade = this._getFilterArmesParade(rollData.competence.data.categorie);
|
||||||
|
for (const arme of this.defender.data.items.filter(filterArmesParade)) {
|
||||||
|
content += "<br><a class='chat-card-button' id='parer-button' data-attackerId='" + this.attackerId + "' data-defenderTokenId='" + this.defenderTokenId + "' data-armeid='" + arme._id + "'>Parer avec " + arme.name + "</a>";
|
||||||
|
}
|
||||||
|
|
||||||
|
// esquive
|
||||||
|
if (rollData.competence.data.categorie == 'melee' || rollData.competence.data.categorie == "lancer" || rollData.competence.data.categorie == 'competencecreature') {
|
||||||
|
content += "<br><a class='chat-card-button' id='esquiver-button' data-attackerId='" + this.attackerId + "' data-defenderTokenId='" + this.defenderTokenId + "'>Esquiver</a>";
|
||||||
|
}
|
||||||
|
|
||||||
|
// encaisser
|
||||||
|
content += "<br><a class='chat-card-button' id='encaisser-button' data-attackerId='" + this.attackerId + "' data-defenderTokenId='" + this.defenderTokenId + "'>Encaisser !</a>";
|
||||||
|
|
||||||
|
content += "</span>"
|
||||||
|
|
||||||
|
let defense = {
|
||||||
|
title: "Défense en combat",
|
||||||
|
content: content,
|
||||||
|
whisper: ChatMessage.getWhisperRecipients(this.defender.name),
|
||||||
|
attackerId: this.attackerId,
|
||||||
|
defenderTokenId: this.defenderTokenId,
|
||||||
|
rollMode: true,
|
||||||
|
rollData: duplicate(rollData)
|
||||||
|
};
|
||||||
|
|
||||||
|
// envoyer le message de defense
|
||||||
|
if (!game.user.isGM || this.defender.hasPlayerOwner) {
|
||||||
|
game.socket.emit("system.foundryvtt-reve-de-dragon", { msg: "msg_defense", data: defense });
|
||||||
|
} else {
|
||||||
|
defense.whisper = [game.user];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (game.user.isGM) { // Always push the message to the MJ
|
||||||
|
ChatMessage.create(defense);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
_getFilterArmesParade(categorie) {
|
||||||
|
switch (categorie) {
|
||||||
|
case 'tir':
|
||||||
|
case 'lancer':
|
||||||
|
return arme => arme.type == "arme" && arme.data.competence.toLowerCase().match("bouclier");
|
||||||
|
default:
|
||||||
|
return arme => (arme.type == "arme" && RdDItemCompetence.isCompetenceMelee(arme.data.competence)) || (arme.type == "competencecreature" && arme.data.isparade)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
_calculMortaliteEncaissement(rollData) {
|
||||||
|
const mortalite = this.defender.isEntiteCauchemar() ? "cauchemar" : (rollData.mortalite ? rollData.mortalite : "mortel");
|
||||||
|
console.log("Mortalité : ", mortalite, this.defender.data.type);
|
||||||
|
return mortalite;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_onAttaqueEchecTotal(rollData) {
|
||||||
|
console.log("RdDCombat.onEchecTotal >>>", rollData);
|
||||||
|
// TODO: proposer un résultat d'échec total
|
||||||
|
let chatOptions = {
|
||||||
|
content: "<strong>Echec total à l'attaque!</strong>"
|
||||||
|
}
|
||||||
|
ChatUtility.chatWithRollMode(chatOptions, this.attacker.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
_onAttaqueEchec(rollData) {
|
||||||
|
console.log("RdDCombat.onAttaqueEchec >>>", rollData);
|
||||||
|
let target = this._getTarget();
|
||||||
|
let chatOptions = {
|
||||||
|
content: "<strong>Test : " + rollData.selectedCarac.label + " / " + rollData.competence.name + "</strong>"
|
||||||
|
+ "<br>Difficultés <strong>libre : " + rollData.diffLibre + "</strong> / conditions : " + Misc.toSignedString(rollData.diffConditions) + " / état : " + rollData.etat
|
||||||
|
+ RdDResolutionTable.explain(rolled)
|
||||||
|
+ (target ? "<br><strong>Cible</strong> : " + this.defender.data.name : "")
|
||||||
|
}
|
||||||
|
ChatUtility.chatWithRollMode(chatOptions, this.attacker.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
async choixParticuliere(rollData, choix) {
|
||||||
|
console.log("RdDCombat.choixParticuliere >>>", rollData, choix);
|
||||||
|
rollData.particuliereAttaque = choix;
|
||||||
|
await this._onAttaqueNormale(rollData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
async parade(attackerRoll, armeParadeId) {
|
||||||
|
let arme = this.defender.getOwnedItem(armeParadeId);
|
||||||
|
|
||||||
|
console.log("RdDCombat.parade >>>", attackerRoll, armeParadeId, arme);
|
||||||
|
|
||||||
|
let rollData = this._prepareParade(attackerRoll, arme);
|
||||||
|
|
||||||
|
const dialog = await RdDRoll.create(this.defender, rollData,
|
||||||
|
{ html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-competence.html' }, {
|
||||||
|
name: 'jet-parade',
|
||||||
|
label: 'Parade: ' + (arme ? arme.name : rollData.competence.name),
|
||||||
|
callbacks: [
|
||||||
|
this.defender.createCallbackExperience(),
|
||||||
|
{ condition: RdDResolutionTable.isParticuliere, action: r => this._onParadeParticuliere(r) },
|
||||||
|
{ condition: RdDResolutionTable.isReussite, action: r => this._onParadeNormale(r) },
|
||||||
|
{ condition: RdDResolutionTable.isEchecTotal, action: r => this._onParadeEchecTotal(r) },
|
||||||
|
{ condition: RdDResolutionTable.isEchec, action: r => this._onParadeEchec(r) }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
dialog.render(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
_prepareParade(attackerRoll, arme) {
|
||||||
|
const isCreature = this.defender.isCreature();
|
||||||
|
const compName = isCreature ? arme.name : arme.data.data.competence;
|
||||||
|
const competence = this.defender.getCompetence(compName);
|
||||||
|
const armeAttaque = attackerRoll.arme;
|
||||||
|
const armeParade = arme.data;
|
||||||
|
|
||||||
|
if (compName != competence.name) {
|
||||||
|
// TODO: toujours utiliser competence.name ...
|
||||||
|
ui.notifications.warn("Différence entre compétence " + competence.name + " et compétence de l'arme " + compName);
|
||||||
|
}
|
||||||
|
|
||||||
|
let rollData = {
|
||||||
|
forceValue: this.defender.getForceValue(),
|
||||||
|
diffLibre: attackerRoll.diffLibre,
|
||||||
|
attackerRoll: attackerRoll,
|
||||||
|
competence: competence,
|
||||||
|
arme: arme.data,
|
||||||
|
demiSurprise: this.defender.isDemiSurprise(),
|
||||||
|
needSignificative: this._needSignificative(attackerRoll) || RdDItemArme.needParadeSignificative(armeAttaque, armeParade),
|
||||||
|
needResist: this._needResist(armeAttaque, armeParade),
|
||||||
|
carac: this.defender.data.data.carac
|
||||||
|
};
|
||||||
|
if (isCreature) {
|
||||||
|
this._prepareRollDataCreature(rollData, competence);
|
||||||
|
}
|
||||||
|
return rollData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
_needSignificative(attackerRoll) {
|
||||||
|
return attackerRoll.particuliereAttaque == 'finesse';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
_needResist(armeAttaque, armeParade) {
|
||||||
|
// Manage weapon categories when parrying (cf. page 115 )
|
||||||
|
let attCategory = RdDItemArme.getCategorieArme(armeAttaque);
|
||||||
|
let defCategory = RdDItemArme.getCategorieArme(armeParade);
|
||||||
|
|
||||||
|
return (attCategory.match("epee") && (defCategory == "hache" || defCategory == "lance"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
_onParadeParticuliere(rollData) {
|
||||||
|
console.log("RdDCombat._onParadeParticuliere >>>", rollData);
|
||||||
|
if (!rollData.attackerRoll.isPart) {
|
||||||
|
// TODO: attaquant doit jouer résistance et peut être désarmé p132
|
||||||
|
}
|
||||||
|
let chatOptions = {
|
||||||
|
content: "<strong>Vous pouvez utiliser votre arme pour une deuxième parade!</strong>"
|
||||||
|
}
|
||||||
|
ChatUtility.chatWithRollMode(chatOptions, this.defender.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
async _onParadeNormale(rollData) {
|
||||||
|
console.log("RdDCombat._onParadeNormale >>>", rollData);
|
||||||
|
if (rollData.needResist && !rollData.rolled.isPart) {
|
||||||
|
// TODO: déplacer la logique détérioration armure dans RdDCombat
|
||||||
|
this.defender.computeDeteriorationArme(rollData);
|
||||||
|
}
|
||||||
|
await this.defender.computeRecul(rollData, false);
|
||||||
|
|
||||||
|
let chatOptions = {
|
||||||
|
content: "<strong>Test : " + rollData.selectedCarac.label + " / " + rollData.competence.name + "</strong>"
|
||||||
|
+ "<br>Difficultés <strong>libre : " + rollData.diffLibre + "</strong> / conditions : " + Misc.toSignedString(rollData.diffConditions) + " / état : " + rollData.etat
|
||||||
|
+ RdDResolutionTable.explain(rollData.rolled)
|
||||||
|
+ "<br><strong>Attaque parée!</strong>"
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatUtility.chatWithRollMode(chatOptions, this.defender.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
_onParadeEchecTotal(rollData) {
|
||||||
|
console.log("RdDCombat._onParadeEchecTotal >>>", rollData);
|
||||||
|
// TODO: proposer un résultat d'échec total
|
||||||
|
let chatOptions = {
|
||||||
|
content: "<strong>Echec total à la parade!</strong>"
|
||||||
|
}
|
||||||
|
ChatUtility.chatWithRollMode(chatOptions, this.defender.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
async _onParadeEchec(rollData) {
|
||||||
|
console.log("RdDCombat._onParadeEchec >>>", rollData);
|
||||||
|
|
||||||
|
let explications = "<br><strong>Parade échouée, encaissement !</strong>";
|
||||||
|
if (rollData.demiSurprise) {
|
||||||
|
explications += " Demi surprise!";
|
||||||
|
}
|
||||||
|
if (rollData.needSignificative) {
|
||||||
|
explications += " Significative nécessaire!";
|
||||||
|
}
|
||||||
|
|
||||||
|
let chatOptions = {
|
||||||
|
content: "<strong>Test : " + rollData.selectedCarac.label + " / " + rollData.competence.name + "</strong>"
|
||||||
|
+ "<br>Difficultés <strong>libre : " + rollData.diffLibre + "</strong> / conditions : " + Misc.toSignedString(rollData.diffConditions) + " / état : " + rollData.etat
|
||||||
|
+ RdDResolutionTable.explain(rollData.rolled)
|
||||||
|
+ explications
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatUtility.chatWithRollMode(chatOptions, this.defender.name)
|
||||||
|
|
||||||
|
await this.defender.computeRecul(rollData, true);
|
||||||
|
// TODO: gestion message pour chance/encaissement
|
||||||
|
this.encaisser(rollData.attackerRoll);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
async esquive(attackerRoll) {
|
||||||
|
let esquive = this.defender.getCompetence("esquive");
|
||||||
|
if (esquive == undefined) {
|
||||||
|
ui.notifications.error(this.defender.name + " n'a pas de compétence 'esquive'");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log("RdDCombat.esquive >>>", attackerRoll, esquive);
|
||||||
|
let rollData = this._prepareEsquive(attackerRoll, esquive);
|
||||||
|
|
||||||
|
const dialog = await RdDRoll.create(this.defender, rollData,
|
||||||
|
{ html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-competence.html' }, {
|
||||||
|
name: 'jet-esquive',
|
||||||
|
label: 'Esquiver',
|
||||||
|
callbacks: [
|
||||||
|
this.defender.createCallbackExperience(),
|
||||||
|
{ condition: RdDResolutionTable.isParticuliere, action: r => this._onEsquiveParticuliere(r) },
|
||||||
|
{ condition: RdDResolutionTable.isReussite, action: r => this._onEsquiveNormale(r) },
|
||||||
|
{ condition: RdDResolutionTable.isEchecTotal, action: r => this._onEsquiveEchecTotal(r) },
|
||||||
|
{ condition: RdDResolutionTable.isEchec, action: r => this._onEsquiveEchec(r) },
|
||||||
|
]
|
||||||
|
});
|
||||||
|
dialog.render(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
_prepareEsquive(attackerRoll, competence) {
|
||||||
|
let rollData = {
|
||||||
|
forceValue: this.defender.getForceValue(),
|
||||||
|
diffLibre: attackerRoll.diffLibre,
|
||||||
|
attackerRoll: attackerRoll,
|
||||||
|
competence: competence,
|
||||||
|
demiSurprise: this.defender.isDemiSurprise(),
|
||||||
|
needSignificative: this._needSignificative(attackerRoll),
|
||||||
|
carac: this.defender.data.data.carac
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.defender.isCreature()) {
|
||||||
|
this._prepareRollDataCreature(rollData, competence);
|
||||||
|
}
|
||||||
|
return rollData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
_onEsquiveParticuliere(rollData) {
|
||||||
|
console.log("RdDCombat._onEsquiveParticuliere >>>", rollData);
|
||||||
|
let chatOptions = {
|
||||||
|
content: "<strong>Vous pouvez esquiver une deuxième attaque!</strong>"
|
||||||
|
}
|
||||||
|
ChatUtility.chatWithRollMode(chatOptions, this.defender.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
_onEsquiveNormale(rollData) {
|
||||||
|
console.log("RdDCombat._onEsquiveNormal >>>", rollData);
|
||||||
|
let chatOptions = {
|
||||||
|
content: "<strong>Test : " + rollData.selectedCarac.label + " / " + rollData.competence.name + "</strong>"
|
||||||
|
+ "<br>Difficultés <strong>libre : " + rollData.diffLibre + "</strong> / conditions : " + Misc.toSignedString(rollData.diffConditions) + " / état : " + rollData.etat
|
||||||
|
+ RdDResolutionTable.explain(rollData.rolled)
|
||||||
|
+ "<br><strong>Attaque esquivée!</strong>"
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatUtility.chatWithRollMode(chatOptions, this.defender.name)
|
||||||
|
}
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
_onEsquiveEchecTotal(rollData) {
|
||||||
|
console.log("RdDCombat._onEsquiveEchecTotal >>>", rollData);
|
||||||
|
// TODO: proposer un résultat d'échec total
|
||||||
|
let chatOptions = {
|
||||||
|
content: "<strong>Echec total à l'esquive'!</strong>"
|
||||||
|
}
|
||||||
|
ChatUtility.chatWithRollMode(chatOptions, this.defender.name)
|
||||||
|
}
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
async _onEsquiveEchec(rollData) {
|
||||||
|
console.log("RdDCombat._onEsquiveEchec >>>", rollData);
|
||||||
|
|
||||||
|
let explications = "<br><strong>Esquive échouée, encaissement !</strong>";
|
||||||
|
if (rollData.demiSurprise) {
|
||||||
|
explications += " Demi surprise!";
|
||||||
|
}
|
||||||
|
if (rollData.needSignificative) {
|
||||||
|
explications += " Significative nécessaire!";
|
||||||
|
}
|
||||||
|
|
||||||
|
let chatOptions = {
|
||||||
|
content: "<strong>Test : " + rollData.selectedCarac.label + " / " + rollData.competence.name + "</strong>"
|
||||||
|
+ "<br>Difficultés <strong>libre : " + rollData.diffLibre + "</strong> / conditions : " + Misc.toSignedString(rollData.diffConditions) + " / état : " + rollData.etat
|
||||||
|
+ RdDResolutionTable.explain(rollData.rolled)
|
||||||
|
+ explications
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatUtility.chatWithRollMode(chatOptions, this.defender.name)
|
||||||
|
|
||||||
|
await this.defender.computeRecul(rollData, true);
|
||||||
|
this.encaisser(rollData.attackerRoll);
|
||||||
|
}
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
encaisser(attackerRoll) {
|
||||||
|
// TODO: gestion message pour chance/encaissement
|
||||||
|
this.encaisser(attackerRoll, this.defenderTokenId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
encaisser(attackerRoll, defenderTokenId) {
|
||||||
|
defenderTokenId = defenderTokenId || this.defenderTokenId;
|
||||||
|
console.log("RdDCombat.encaisser >>>", attackerRoll, defenderTokenId);
|
||||||
|
|
||||||
|
if (game.user.isGM) { // Current user is the GM -> direct access
|
||||||
|
attackerRoll.attackerId = this.attackerId;
|
||||||
|
attackerRoll.defenderTokenId = defenderTokenId;
|
||||||
|
this.defender.encaisserDommages(attackerRoll, this.attacker);
|
||||||
|
} else { // Emit message for GM
|
||||||
|
game.socket.emit("system.foundryvtt-reve-de-dragon", {
|
||||||
|
msg: "msg_encaisser",
|
||||||
|
data: { attackerId: this.attackerId, defenderTokenId: defenderTokenId }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/* retourne true si on peut continuer, false si on ne peut pas continuer */
|
||||||
|
async accorderEntite(when = 'avant-encaissement') {
|
||||||
|
if (when != game.settings.get("foundryvtt-reve-de-dragon", "accorder-entite-cauchemar")
|
||||||
|
|| this.defender == undefined
|
||||||
|
|| !this.defender.isEntiteCauchemar()
|
||||||
|
|| this.defender.isEntiteCauchemarAccordee(this.attacker)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let rolled = await RdDResolutionTable.roll(this.attacker.getReveActuel(), - Number(this.defender.data.data.carac.niveau.value));
|
||||||
|
|
||||||
|
let message = {
|
||||||
|
content: "Jet de points actuels de rêve à " + rolled.finalLevel + RdDResolutionTable.explain(rolled) + "<br>",
|
||||||
|
whisper: ChatMessage.getWhisperRecipients(this.attacker.name)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (rolled.isSuccess) {
|
||||||
|
await this.defender.setEntiteReveAccordee(this.attacker);
|
||||||
|
message.content += this.attacker.name + " s'est accordé avec " + this.defender.name;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
message.content += this.attacker.name + " n'est pas accordé avec " + this.defender.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatMessage.create(message);
|
||||||
|
return rolled.isSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -123,25 +123,41 @@ Hooks.once("init", async function() {
|
|||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
game.settings.register("foundryvtt-reve-de-dragon", "calendrier", {
|
game.settings.register("foundryvtt-reve-de-dragon", "calendrier", {
|
||||||
name: "calendrier",
|
name: "calendrier",
|
||||||
scope: "world",
|
scope: "world",
|
||||||
config: false,
|
config: false,
|
||||||
type: Object
|
type: Object
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
game.settings.register("foundryvtt-reve-de-dragon", "liste-nombre-astral", {
|
game.settings.register("foundryvtt-reve-de-dragon", "liste-nombre-astral", {
|
||||||
name: "liste-nombre-astral",
|
name: "liste-nombre-astral",
|
||||||
scope: "world",
|
scope: "world",
|
||||||
config: false,
|
config: false,
|
||||||
type: Object
|
type: Object
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
game.settings.register("foundryvtt-reve-de-dragon", "calendrier-pos", {
|
game.settings.register("foundryvtt-reve-de-dragon", "calendrier-pos", {
|
||||||
name: "calendrierPos",
|
name: "calendrierPos",
|
||||||
scope: "world",
|
scope: "world",
|
||||||
config: false,
|
config: false,
|
||||||
type: Object
|
type: Object
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
game.settings.register("foundryvtt-reve-de-dragon", "moteur-combat", {
|
||||||
|
name: "Utiliser le moteur de combat",
|
||||||
|
scope: "world",
|
||||||
|
config: true,
|
||||||
|
type: String,
|
||||||
|
choices: { // If choices are defined, the resulting setting will be a select menu
|
||||||
|
"standard": "Standard",
|
||||||
|
"experimental": "Expérimental"
|
||||||
|
},
|
||||||
|
default: "standard"
|
||||||
|
});
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
game.settings.register("foundryvtt-reve-de-dragon", "dice-so-nice", {
|
game.settings.register("foundryvtt-reve-de-dragon", "dice-so-nice", {
|
||||||
name: "Montrer les dés pour toutes les jets",
|
name: "Montrer les dés pour toutes les jets",
|
||||||
@ -151,6 +167,7 @@ Hooks.once("init", async function() {
|
|||||||
default: false,
|
default: false,
|
||||||
type: Boolean
|
type: Boolean
|
||||||
});
|
});
|
||||||
|
|
||||||
//game.settings.get("<systemName>","<settingName>") to retrieve it and game.settings.set("<systemName>","<settingName>", <newValue>)
|
//game.settings.get("<systemName>","<settingName>") to retrieve it and game.settings.set("<systemName>","<settingName>", <newValue>)
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
@ -42,13 +42,13 @@ const specialResults = [
|
|||||||
|
|
||||||
|
|
||||||
const reussites = [
|
const reussites = [
|
||||||
{ code: "etotal", isPart: false, isSign: false, isSuccess: false, isEchec: true, isEPart: true, isETotal: true, ptTache: -4, ptQualite: -6, quality: "Echec total", condition: (target, roll) => roll >= target.etotal && roll <= 100 },
|
{ code: "etotal", isPart: false, isSign: false, isSuccess: false, isEchec: true, isEPart: true, isETotal: true, ptTache: -4, ptQualite: -6, quality: "Echec total", condition: (target, roll) => roll >= target.etotal && roll <= 100 },
|
||||||
{ code: "epart", isPart: false, isSign: false, isSuccess: false, isEchec: true, isEPart: true, isETotal: false, ptTache: -2, ptQualite: -4, quality: "Echec particulier", condition: (target, roll) => (roll >= target.epart && roll < target.etotal) },
|
{ code: "epart", isPart: false, isSign: false, isSuccess: false, isEchec: true, isEPart: true, isETotal: false, ptTache: -2, ptQualite: -4, quality: "Echec particulier", condition: (target, roll) => (roll >= target.epart && roll < target.etotal) },
|
||||||
{ code: "echec", isPart: false, isSign: false, isSuccess: false, isEchec: true, isEPart: false, isETotal: false, ptTache: 0, ptQualite: -2, quality: "Echec normal", condition: (target, roll) => (roll > target.score && roll < target.etotal) },
|
{ code: "echec", isPart: false, isSign: false, isSuccess: false, isEchec: true, isEPart: false, isETotal: false, ptTache: 0, ptQualite: -2, quality: "Echec normal", condition: (target, roll) => (roll > target.score && roll < target.etotal) },
|
||||||
{ code: "norm", isPart: false, isSign: false, isSuccess: true, isEchec: false, isEPart: false, isETotal: false, ptTache: 1, ptQualite: 0, quality: "Réussite normale", condition: (target, roll) => (roll > target.sign && roll <= target.score) },
|
{ code: "norm", isPart: false, isSign: false, isSuccess: true, isEchec: false, isEPart: false, isETotal: false, ptTache: 1, ptQualite: 0, quality: "Réussite normale", condition: (target, roll) => (roll > target.sign && roll <= target.score) },
|
||||||
{ code: "sign", isPart: false, isSign: true, isSuccess: true, isEchec: false, isEPart: false, isETotal: false, ptTache: 2, ptQualite: 1, quality: "Réussite significative", condition: (target, roll) => (roll > target.part && roll <= target.sign) },
|
{ code: "sign", isPart: false, isSign: true, isSuccess: true, isEchec: false, isEPart: false, isETotal: false, ptTache: 2, ptQualite: 1, quality: "Réussite significative", condition: (target, roll) => (roll > target.part && roll <= target.sign) },
|
||||||
{ code: "part", isPart: true, isSign: true, isSuccess: true, isEchec: false, isEPart: false, isETotal: false, ptTache: 3, ptQualite: 2, quality: "Réussite Particulière!", condition: (target, roll) => (roll > 0 && roll <= target.part) },
|
{ code: "part", isPart: true, isSign: true, isSuccess: true, isEchec: false, isEPart: false, isETotal: false, ptTache: 3, ptQualite: 2, quality: "Réussite Particulière!", condition: (target, roll) => (roll > 0 && roll <= target.part) },
|
||||||
{ code: "error", isPart: false, isSign: false, isSuccess: false, isEchec: true, isEPart: true, isETotal: true, ptTache: 0, ptQualite: 0, quality: "Jet de dés invalide", condition: (target, roll) => (roll <= 0 || roll > 100) }
|
{ code: "error", isPart: false, isSign: false, isSuccess: false, isEchec: true, isEPart: true, isETotal: true, ptTache: 0, ptQualite: 0, quality: "Jet de dés invalide", condition: (target, roll) => (roll <= 0 || roll > 100) }
|
||||||
];
|
];
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@ -81,8 +81,9 @@ export class RdDResolutionTable {
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static explain(rolled) {
|
static explain(rolled) {
|
||||||
let message = "<br>Jet : <strong>" + rolled.roll + "</strong> sur " + rolled.score + "% ";
|
let message = "<br>Jet : <strong>" + rolled.roll + "</strong> sur " + rolled.score + "% ";
|
||||||
if (rolled.caracValue != null && rolled.finalLevel!= null) {
|
if (rolled.caracValue != null && rolled.finalLevel != null) {
|
||||||
message += "(" + rolled.caracValue + " à " + Misc.toSignedString(rolled.finalLevel) + ") ";
|
message += (rolled.needSignificative ? "(significative sur " : "(")
|
||||||
|
+ rolled.caracValue + " à " + Misc.toSignedString(rolled.finalLevel) + ") ";
|
||||||
}
|
}
|
||||||
message += '<strong>' + rolled.quality + '</strong>'
|
message += '<strong>' + rolled.quality + '</strong>'
|
||||||
return message;
|
return message;
|
||||||
@ -90,28 +91,39 @@ export class RdDResolutionTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static updateChancesWithBonus( chances, bonus ) {
|
static async rollData(rollData) {
|
||||||
if (bonus) {
|
rollData.rolled = await this.roll(rollData.caracValue, rollData.finalLevel, rollData.bonus, rollData.needSignificative);
|
||||||
let newScore = Number(chances.score) + Number(bonus);
|
}
|
||||||
mergeObject(chances, this._computeCell(null, newScore), {overwrite: true});
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
static async roll(caracValue, finalLevel, bonus = undefined, needSignificative = undefined, showDice = true) {
|
||||||
|
let chances = this.computeChances(caracValue, finalLevel);
|
||||||
|
this._updateChancesWithBonus(chances, bonus);
|
||||||
|
this._updateChancesNeedSignificative(chances, needSignificative);
|
||||||
|
chances.showDice = showDice;
|
||||||
|
|
||||||
|
let rolled = await this.rollChances(chances);
|
||||||
|
rolled.caracValue = caracValue;
|
||||||
|
rolled.finalLevel = finalLevel;
|
||||||
|
rolled.bonus = bonus;
|
||||||
|
rolled.needSignificative = needSignificative;
|
||||||
|
return rolled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
static _updateChancesNeedSignificative(chances, needSignificative) {
|
||||||
|
if (needSignificative) {
|
||||||
|
let newScore = Math.floor(Number(chances.score) / 2);
|
||||||
|
mergeObject(chances, this._computeCell(null, newScore), { overwrite: true });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static async rollData(rollData ) {
|
static _updateChancesWithBonus(chances, bonus) {
|
||||||
rollData.rolled = await this.roll(rollData.caracValue, rollData.finalLevel, rollData.bonus);
|
if (bonus) {
|
||||||
}
|
let newScore = Number(chances.score) + Number(bonus);
|
||||||
|
mergeObject(chances, this._computeCell(null, newScore), { overwrite: true });
|
||||||
/* -------------------------------------------- */
|
}
|
||||||
static async roll(caracValue, finalLevel, bonus = undefined, showDice = true ) {
|
|
||||||
let chances = this.computeChances(caracValue, finalLevel);
|
|
||||||
chances.showDice = showDice;
|
|
||||||
this.updateChancesWithBonus( chances, bonus);
|
|
||||||
let rolled = await this.rollChances(chances);
|
|
||||||
rolled.caracValue = caracValue;
|
|
||||||
rolled.finalLevel = finalLevel;
|
|
||||||
rolled.bonus = bonus;
|
|
||||||
return rolled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@ -146,6 +158,23 @@ export class RdDResolutionTable {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static isEchec(rollData) {
|
||||||
|
return rollData.demiSurprise ? !rollData.rolled.isSign : rollData.rolled.isEchec;
|
||||||
|
}
|
||||||
|
|
||||||
|
static isEchecTotal(rollData) {
|
||||||
|
return (rollData.demiSurprise && rollData.arme) ? rollData.rolled.isEchec : rollData.rolled.isETotal;
|
||||||
|
}
|
||||||
|
|
||||||
|
static isParticuliere(rollData) {
|
||||||
|
return (rollData.demiSurprise && rollData.arme) ? false : rollData.rolled.isPart;
|
||||||
|
}
|
||||||
|
|
||||||
|
static isReussite(rollData) {
|
||||||
|
return rollData.demiSurprise ? rollData.rolled.isSign : rollData.rolled.isSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static _computeReussite(chances, roll) {
|
static _computeReussite(chances, roll) {
|
||||||
const reussite = reussites.find(x => x.condition(chances, roll));
|
const reussite = reussites.find(x => x.condition(chances, roll));
|
||||||
|
@ -33,13 +33,17 @@ export class RdDRollDialog extends Dialog {
|
|||||||
if (mode == "competence") {
|
if (mode == "competence") {
|
||||||
dialogConf.title = "Test de compétence"
|
dialogConf.title = "Test de compétence"
|
||||||
dialogOptions.height = 430
|
dialogOptions.height = 430
|
||||||
|
ui.notifications.warn("RdDRollDialog - Plus utilisé pour les compétences")
|
||||||
|
|
||||||
} else if (mode == "arme") {
|
} else if (mode == "arme") {
|
||||||
dialogConf.title = "Test de combat/arme"
|
dialogConf.title = "Test de combat/arme"
|
||||||
dialogOptions.height = 460
|
dialogOptions.height = 460
|
||||||
} else if (mode == "carac") {
|
} else if (mode == "carac") {
|
||||||
|
ui.notifications.warn("RdDRollDialog - Plus utilisé pour les caractéristiques")
|
||||||
dialogConf.title = "Test de caractéristique"
|
dialogConf.title = "Test de caractéristique"
|
||||||
dialogOptions.height = 420
|
dialogOptions.height = 420
|
||||||
} else if (mode == "sort") {
|
} else if (mode == "sort") {
|
||||||
|
ui.notifications.warn("RdDRollDialog - Plus utilisé pour les sorts")
|
||||||
dialogConf.title = "Lancer un sort"
|
dialogConf.title = "Lancer un sort"
|
||||||
dialogOptions.height = 460
|
dialogOptions.height = 460
|
||||||
}
|
}
|
||||||
@ -146,7 +150,7 @@ export class RdDRollDialog extends Dialog {
|
|||||||
updateRollResult(rollData);
|
updateRollResult(rollData);
|
||||||
});
|
});
|
||||||
html.find('#coupsNonMortels').change((event) => {
|
html.find('#coupsNonMortels').change((event) => {
|
||||||
this.rollData.mortalite = event.currentTarget.checked ? "non-mortel" : "non-mortel";
|
this.rollData.mortalite = event.currentTarget.checked ? "non-mortel" : "mortel";
|
||||||
});
|
});
|
||||||
html.find('#isCharge').change((event) => {
|
html.find('#isCharge').change((event) => {
|
||||||
this.rollData.isCharge = event.currentTarget.checked;
|
this.rollData.isCharge = event.currentTarget.checked;
|
||||||
|
@ -33,19 +33,27 @@ export class RdDRoll extends Dialog {
|
|||||||
ajustementsConditions: CONFIG.RDD.ajustementsConditions,
|
ajustementsConditions: CONFIG.RDD.ajustementsConditions,
|
||||||
difficultesLibres: CONFIG.RDD.difficultesLibres,
|
difficultesLibres: CONFIG.RDD.difficultesLibres,
|
||||||
etat: actor.data.data.compteurs.etat.value,
|
etat: actor.data.data.compteurs.etat.value,
|
||||||
|
carac: actor.data.data.carac,
|
||||||
finalLevel: 0,
|
finalLevel: 0,
|
||||||
diffConditions: 0,
|
diffConditions: 0,
|
||||||
diffLibre: 0,
|
diffLibre: 0,
|
||||||
|
forceValue : actor.getForceValue(),
|
||||||
malusArmureValue: (actor.type == 'personnage ' && actor.data.data.attributs && actor.data.data.attributs.malusarmure) ? actor.data.data.attributs.malusarmure.value : 0,
|
malusArmureValue: (actor.type == 'personnage ' && actor.data.data.attributs && actor.data.data.attributs.malusarmure) ? actor.data.data.attributs.malusarmure.value : 0,
|
||||||
surencMalusFlag: actor.type == 'personnage ' ? (actor.data.data.compteurs.surenc.value < 0) : false,
|
surencMalusFlag: actor.type == 'personnage ' ? (actor.data.data.compteurs.surenc.value < 0) : false,
|
||||||
surencMalusValue: actor.type == 'personnage ' ? actor.data.data.compteurs.surenc.value : 0,
|
surencMalusValue: actor.type == 'personnage ' ? actor.data.data.compteurs.surenc.value : 0,
|
||||||
surencMalusApply: false,
|
surencMalusApply: false,
|
||||||
isNatation: rollData.competence ? rollData.competence.name.toLowerCase().includes("natation") : false,
|
isNatation: rollData.competence ? rollData.competence.name.toLowerCase().includes("natation") : false,
|
||||||
useEncForNatation: false,
|
useEncForNatation: false,
|
||||||
encValueForNatation: actor.encombrementTotal ? Math.floor(actor.encombrementTotal) : 0,
|
encValueForNatation: actor.encombrementTotal ? Math.floor(actor.encombrementTotal) : 0
|
||||||
ajustementAstrologique: actor.ajustementAstrologique()
|
// ,
|
||||||
|
// ajustementAstrologique: actor.ajustementAstrologique()
|
||||||
},
|
},
|
||||||
{ overwrite: false });
|
{ overwrite: false });
|
||||||
|
|
||||||
|
if (actor.isEntiteCauchemar())
|
||||||
|
{
|
||||||
|
rollData.needSignificative = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@ -181,7 +189,10 @@ export class RdDRoll extends Dialog {
|
|||||||
updateRollResult(rollData);
|
updateRollResult(rollData);
|
||||||
});
|
});
|
||||||
html.find('#coupsNonMortels').change((event) => {
|
html.find('#coupsNonMortels').change((event) => {
|
||||||
this.rollData.mortalite = event.currentTarget.checked ? "non-mortel" : "non-mortel";
|
this.rollData.mortalite = event.currentTarget.checked ? "non-mortel" : "mortel";
|
||||||
|
});
|
||||||
|
html.find('#isCharge').change((event) => {
|
||||||
|
this.rollData.isCharge = event.currentTarget.checked;
|
||||||
});
|
});
|
||||||
html.find('#surencMalusApply').change((event) => {
|
html.find('#surencMalusApply').change((event) => {
|
||||||
this.rollData.surencMalusApply = event.currentTarget.checked;
|
this.rollData.surencMalusApply = event.currentTarget.checked;
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
import { TMRUtility } from "./tmr-utility.js";
|
import { TMRUtility } from "./tmr-utility.js";
|
||||||
import { RdDRollTables } from "./rdd-rolltables.js";
|
import { RdDRollTables } from "./rdd-rolltables.js";
|
||||||
import { ChatUtility } from "./chat-utility.js";
|
import { ChatUtility } from "./chat-utility.js";
|
||||||
import { Misc } from "./misc.js";
|
import { RdDItemCompetence } from "./item-competence.js";
|
||||||
|
import { RdDCombat } from "./rdd-combat.js";
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
const level_category = {
|
const level_category = {
|
||||||
@ -635,35 +636,6 @@ export class RdDUtility {
|
|||||||
return compList.find(item => item.name.toLowerCase() == compName && (item.type =="competence" || item.type == "competencecreature"))
|
return compList.find(item => item.name.toLowerCase() == compName && (item.type =="competence" || item.type == "competencecreature"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
static getArmeCategory( arme )
|
|
||||||
{
|
|
||||||
if ( arme.data.competence == undefined) return 'competencecreature';
|
|
||||||
|
|
||||||
let compname = arme.data.competence.toLowerCase();
|
|
||||||
if ( compname.match("hache") ) return "hache";
|
|
||||||
if ( compname.match("hast") ) return "hast";
|
|
||||||
if ( compname.match("lance") ) return "lance";
|
|
||||||
if ( compname.match("bouclier") ) return "bouclier";
|
|
||||||
if ( compname.match("masse") ) return "masse";
|
|
||||||
if ( compname.match("fléau") ) return "fleau";
|
|
||||||
if ( compname.match("epée") ) {
|
|
||||||
let armename = arme.name.toLowerCase();
|
|
||||||
if (armename == "dague" || armename.match("gnome") )
|
|
||||||
return "epee_courte";
|
|
||||||
}
|
|
||||||
return "epee_longue";
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
static isArmeMelee( compName)
|
|
||||||
{
|
|
||||||
let comp = compName.toLowerCase();
|
|
||||||
if (comp.match("epée") || comp.match("épée") || comp.match("hache") || comp.match("fleau") || comp.match("mass") || comp.match("lance") || comp.match("hast") || comp == "dague" || comp=="bouclier")
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static buildDefenseChatCard( attacker, target, rollData )
|
static buildDefenseChatCard( attacker, target, rollData )
|
||||||
{
|
{
|
||||||
@ -671,9 +643,9 @@ export class RdDUtility {
|
|||||||
let myTarget = target.actor;
|
let myTarget = target.actor;
|
||||||
let defenseMsg = { title: "Défense en combat",
|
let defenseMsg = { title: "Défense en combat",
|
||||||
content: "<strong>"+myTarget.name+"</strong> doit se défendre : <br><span class='chat-card-button-area'>" +
|
content: "<strong>"+myTarget.name+"</strong> doit se défendre : <br><span class='chat-card-button-area'>" +
|
||||||
"<a class='chat-card-button' id='encaisser-button' data-attackerid='"+attacker.data._id + "' data-defendertokenid='" + target.data._id + "'>Encaisser !</a></span>",
|
"<a class='chat-card-button' id='encaisser-button' data-attackerId='"+attacker.data._id + "' data-defenderTokenId='" + target.data._id + "'>Encaisser !</a></span>",
|
||||||
whisper: ChatMessage.getWhisperRecipients( myTarget.name ),
|
whisper: ChatMessage.getWhisperRecipients( myTarget.name ),
|
||||||
attackerid: attacker.data._id,
|
attackerId: attacker.data._id,
|
||||||
defenderTokenId: target.data._id,
|
defenderTokenId: target.data._id,
|
||||||
rollMode: true
|
rollMode: true
|
||||||
};
|
};
|
||||||
@ -681,22 +653,22 @@ export class RdDUtility {
|
|||||||
if ( rollData.competence.data.categorie == 'melee' || rollData.competence.data.categorie == 'competencecreature') { // Melee attack or creature
|
if ( rollData.competence.data.categorie == 'melee' || rollData.competence.data.categorie == 'competencecreature') { // Melee attack or creature
|
||||||
let defenderArmes = [];
|
let defenderArmes = [];
|
||||||
for (const arme of myTarget.data.items) {
|
for (const arme of myTarget.data.items) {
|
||||||
if (arme.type == "arme" && this.isArmeMelee(arme.data.competence)) {
|
if (arme.type == "arme" && RdDItemCompetence.isCompetenceMelee(arme.data.competence)) {
|
||||||
defenderArmes.push( arme );
|
defenderArmes.push( arme );
|
||||||
defenseMsg.content += "<br><a class='chat-card-button' id='parer-button' data-attackerid='"+attacker.data._id + "' data-defendertokenid='" + target.data._id + "' data-armeid='"+arme._id+"'>Parer avec " + arme.name + "</a></span>";
|
defenseMsg.content += "<br><a class='chat-card-button' id='parer-button' data-attackerId='"+attacker.data._id + "' data-defenderTokenId='" + target.data._id + "' data-armeid='"+arme._id+"'>Parer avec " + arme.name + "</a></span>";
|
||||||
}
|
}
|
||||||
if (arme.type == "competencecreature" && arme.data.isparade) {
|
if (arme.type == "competencecreature" && arme.data.isparade) {
|
||||||
defenderArmes.push( arme );
|
defenderArmes.push( arme );
|
||||||
defenseMsg.content += "<br><a class='chat-card-button' id='parer-button' data-attackerid='"+attacker.data._id + "' data-defendertokenid='" + target.data._id + "' data-armeid='"+arme._id+"'>Parer avec " + arme.name + "</a></span>";
|
defenseMsg.content += "<br><a class='chat-card-button' id='parer-button' data-attackerId='"+attacker.data._id + "' data-defenderTokenId='" + target.data._id + "' data-armeid='"+arme._id+"'>Parer avec " + arme.name + "</a></span>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
defenseMsg.content += "<br><a class='chat-card-button' id='esquiver-button' data-attackerid='"+attacker.data._id + "' data-defendertokenid='" + target.data._id + "'>Esquiver</a></span>";
|
defenseMsg.content += "<br><a class='chat-card-button' id='esquiver-button' data-attackerId='"+attacker.data._id + "' data-defenderTokenId='" + target.data._id + "'>Esquiver</a></span>";
|
||||||
}
|
}
|
||||||
if ( rollData.competence.data.categorie == "tir" ) {
|
if ( rollData.competence.data.categorie == "tir" ) {
|
||||||
for (const arme of myTarget.data.items) { // Bouclier for parry
|
for (const arme of myTarget.data.items) { // Bouclier for parry
|
||||||
if ( arme.type == "arme" && arme.name.toLowerCase.match("bouclier") ) {
|
if ( arme.type == "arme" && arme.name.toLowerCase.match("bouclier") ) {
|
||||||
defenderArmes.push( arme );
|
defenderArmes.push( arme );
|
||||||
defenseMsg.content += "<br><a class='chat-card-button' id='parer-button' data-attackerid='"+attacker.data._id + "' data-defendertokenid='" + target.data._id + "' data-armeid='"+arme._id+"'>Parer avec " + arme.name + "</a></span>";
|
defenseMsg.content += "<br><a class='chat-card-button' id='parer-button' data-attackerId='"+attacker.data._id + "' data-defenderTokenId='" + target.data._id + "' data-armeid='"+arme._id+"'>Parer avec " + arme.name + "</a></span>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -704,10 +676,10 @@ export class RdDUtility {
|
|||||||
for (const arme of myTarget.data.items) { // Bouclier for parry Dodge/Esquive
|
for (const arme of myTarget.data.items) { // Bouclier for parry Dodge/Esquive
|
||||||
if ( arme.type == "arme" && arme.name.toLowerCase.match("bouclier") ) {
|
if ( arme.type == "arme" && arme.name.toLowerCase.match("bouclier") ) {
|
||||||
defenderArmes.push( arme );
|
defenderArmes.push( arme );
|
||||||
defenseMsg.content += "<br><a class='chat-card-button' id='parer-button' data-attackerid='"+attacker.data._id + "' data-defendertokenid='" + target.data._id + "' data-armeid='"+arme._id+"'>Parer avec " + arme.name + "</a></span>";
|
defenseMsg.content += "<br><a class='chat-card-button' id='parer-button' data-attackerId='"+attacker.data._id + "' data-defenderTokenId='" + target.data._id + "' data-armeid='"+arme._id+"'>Parer avec " + arme.name + "</a></span>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
defenseMsg.content += "<br><a class='chat-card-button' id='esquiver-button' data-attackerid='"+attacker.data._id + "' data-defendertokenid='" + target.data._id + "'>Esquiver</a></span>";
|
defenseMsg.content += "<br><a class='chat-card-button' id='esquiver-button' data-attackerId='"+attacker.data._id + "' data-defenderTokenId='" + target.data._id + "'>Esquiver</a></span>";
|
||||||
}
|
}
|
||||||
|
|
||||||
defenseMsg.toSocket = true; // True per default for all players
|
defenseMsg.toSocket = true; // True per default for all players
|
||||||
@ -754,7 +726,7 @@ export class RdDUtility {
|
|||||||
}
|
}
|
||||||
if ((game.user.isGM && !defenderToken.actor.hasPlayerOwner) || (defenderToken.actor.hasPlayerOwner && (game.user.character.id == defenderToken.actor.data._id))) {
|
if ((game.user.isGM && !defenderToken.actor.hasPlayerOwner) || (defenderToken.actor.hasPlayerOwner && (game.user.character.id == defenderToken.actor.data._id))) {
|
||||||
console.log("User is pushing message...", game.user.name);
|
console.log("User is pushing message...", game.user.name);
|
||||||
game.system.rdd.rollDataHandler[data.attackerid] = duplicate(data.rollData);
|
game.system.rdd.rollDataHandler[data.attackerId] = duplicate(data.rollData);
|
||||||
data.whisper = [game.user];
|
data.whisper = [game.user];
|
||||||
data.blind = true;
|
data.blind = true;
|
||||||
data.rollMode = "blindroll";
|
data.rollMode = "blindroll";
|
||||||
@ -865,7 +837,7 @@ export class RdDUtility {
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static _handleMsgEncaisser(data) {
|
static _handleMsgEncaisser(data) {
|
||||||
if (game.user.isGM) { // Seul le GM effectue l'encaissement sur la fiche
|
if (game.user.isGM) { // Seul le GM effectue l'encaissement sur la fiche
|
||||||
let rollData = game.system.rdd.rollDataHandler[data.attackerid]; // Retrieve the rolldata from the store
|
let rollData = game.system.rdd.rollDataHandler[data.attackerId]; // Retrieve the rolldata from the store
|
||||||
let defenderToken = canvas.tokens.get(data.defenderTokenId);
|
let defenderToken = canvas.tokens.get(data.defenderTokenId);
|
||||||
defenderToken.actor.encaisserDommages(rollData);
|
defenderToken.actor.encaisserDommages(rollData);
|
||||||
}
|
}
|
||||||
@ -874,48 +846,54 @@ export class RdDUtility {
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static async chatListeners( html )
|
static async chatListeners( html )
|
||||||
{
|
{
|
||||||
|
RdDCombat.registerChatCallbacks(html);
|
||||||
|
|
||||||
html.on("click", '#encaisser-button', event => {
|
html.on("click", '#encaisser-button', event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
let attackerid = event.currentTarget.attributes['data-attackerid'].value;
|
if (RdDCombat.isActive()) return;
|
||||||
let defenderTokenId = event.currentTarget.attributes['data-defendertokenid'].value;
|
let attackerId = event.currentTarget.attributes['data-attackerId'].value;
|
||||||
|
let defenderTokenId = event.currentTarget.attributes['data-defenderTokenId'].value;
|
||||||
if ( game.user.isGM ) { // Current user is the GM -> direct access
|
if ( game.user.isGM ) { // Current user is the GM -> direct access
|
||||||
let rollData = game.system.rdd.rollDataHandler[attackerid];
|
let rollData = game.system.rdd.rollDataHandler[attackerId];
|
||||||
rollData.attackerid = attackerid;
|
rollData.attackerId = attackerId;
|
||||||
rollData.defenderTokenId = defenderTokenId;
|
rollData.defenderTokenId = defenderTokenId;
|
||||||
let defenderToken = canvas.tokens.get( defenderTokenId );
|
let defenderToken = canvas.tokens.get( defenderTokenId );
|
||||||
defenderToken.actor.encaisserDommages( rollData, game.actors.get(attackerid));
|
defenderToken.actor.encaisserDommages( rollData, game.actors.get(attackerId));
|
||||||
} else { // Emit message for GM
|
} else { // Emit message for GM
|
||||||
game.socket.emit("system.foundryvtt-reve-de-dragon", {
|
game.socket.emit("system.foundryvtt-reve-de-dragon", {
|
||||||
msg: "msg_encaisser",
|
msg: "msg_encaisser",
|
||||||
data: { attackerid: attackerid, defenderTokenId: defenderTokenId }
|
data: { attackerId: attackerId, defenderTokenId: defenderTokenId }
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
html.on("click", '#parer-button', event => {
|
html.on("click", '#parer-button', event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
let attackerid = event.currentTarget.attributes['data-attackerid'].value;
|
if (RdDCombat.isActive()) return;
|
||||||
|
let attackerId = event.currentTarget.attributes['data-attackerId'].value;
|
||||||
let defenderToken = canvas.tokens.get(event.currentTarget.attributes['data-defenderTokenId'].value );
|
let defenderToken = canvas.tokens.get(event.currentTarget.attributes['data-defenderTokenId'].value );
|
||||||
let armeId = event.currentTarget.attributes['data-armeid'].value;
|
let armeId = event.currentTarget.attributes['data-armeid'].value;
|
||||||
let rollData = game.system.rdd.rollDataHandler[attackerid];
|
let rollData = game.system.rdd.rollDataHandler[attackerId];
|
||||||
defenderToken.actor.parerAttaque( rollData, armeId, game.actors.get(attackerid));
|
defenderToken.actor.parerAttaque( rollData, armeId, game.actors.get(attackerId));
|
||||||
});
|
});
|
||||||
|
|
||||||
html.on("click", '#esquiver-button', event => {
|
html.on("click", '#esquiver-button', event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
let attackerid = event.currentTarget.attributes['data-attackerid'].value;
|
if (RdDCombat.isActive()) return;
|
||||||
|
let attackerId = event.currentTarget.attributes['data-attackerId'].value;
|
||||||
let defenderToken = canvas.tokens.get(event.currentTarget.attributes['data-defenderTokenId'].value );
|
let defenderToken = canvas.tokens.get(event.currentTarget.attributes['data-defenderTokenId'].value );
|
||||||
let rollData = game.system.rdd.rollDataHandler[attackerid];
|
let rollData = game.system.rdd.rollDataHandler[attackerId];
|
||||||
//console.log("Esquive !", rollData, defenderActor);
|
//console.log("Esquive !", rollData, defenderActor);
|
||||||
defenderToken.actor.esquiverAttaque( rollData, game.actors.get(attackerid));
|
defenderToken.actor.esquiverAttaque( rollData, game.actors.get(attackerId));
|
||||||
});
|
});
|
||||||
|
|
||||||
html.on("click", '#particuliere-attaque', event => {
|
html.on("click", '#particuliere-attaque', event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
let attackerid = event.currentTarget.attributes['data-attackerid'].value;
|
if (RdDCombat.isActive()) return;
|
||||||
let attackerActor = game.actors.get(event.currentTarget.attributes['data-attackerid'].value );
|
let attackerId = event.currentTarget.attributes['data-attackerId'].value;
|
||||||
let rollData = game.system.rdd.rollDataHandler[attackerid];
|
let attackerActor = game.actors.get(event.currentTarget.attributes['data-attackerId'].value );
|
||||||
rollData.particuliereAttaque = game.actors.get(event.currentTarget.attributes['data-mode'].value );
|
let rollData = game.system.rdd.rollDataHandler[attackerId];
|
||||||
|
rollData.particuliereAttaque = event.currentTarget.attributes['data-mode'].value;
|
||||||
//console.log("Particulère !", rollData);
|
//console.log("Particulère !", rollData);
|
||||||
attackerActor.continueRoll( rollData );
|
attackerActor.continueRoll( rollData );
|
||||||
});
|
});
|
||||||
@ -926,7 +904,6 @@ export class RdDUtility {
|
|||||||
let actor = game.actors.get( actorId );
|
let actor = game.actors.get( actorId );
|
||||||
actor.tmrApp.forceDemiRevePosition(coord);
|
actor.tmrApp.forceDemiRevePosition(coord);
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@ -942,7 +919,7 @@ export class RdDUtility {
|
|||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
/* Manage chat commands */
|
/* Manage chat commands */
|
||||||
static processChatCommand( commands, content, msg ) {
|
static processChatCommand( commands, content, msg ) {
|
||||||
// Setup new message's visibility
|
// Setup new message's visibility
|
||||||
let rollMode = game.settings.get("core", "rollMode");
|
let rollMode = game.settings.get("core", "rollMode");
|
||||||
if (["gmroll", "blindroll"].includes(rollMode)) msg["whisper"] = ChatMessage.getWhisperRecipients("GM");
|
if (["gmroll", "blindroll"].includes(rollMode)) msg["whisper"] = ChatMessage.getWhisperRecipients("GM");
|
||||||
|
Loading…
Reference in New Issue
Block a user