Merge branch 'nombreux-fixes' into 'v1.3'
Nombreux fixes See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!155
This commit is contained in:
commit
eab8cb7c15
@ -9,6 +9,7 @@ import { RdDItemArme } from "./item-arme.js";
|
|||||||
import { RdDItemCompetence } from "./item-competence.js";
|
import { RdDItemCompetence } from "./item-competence.js";
|
||||||
import { RdDBonus } from "./rdd-bonus.js";
|
import { RdDBonus } from "./rdd-bonus.js";
|
||||||
import { Misc } from "./misc.js";
|
import { Misc } from "./misc.js";
|
||||||
|
import { RdDCombatManager } from "./rdd-combat.js";
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
export class RdDActorSheet extends ActorSheet {
|
export class RdDActorSheet extends ActorSheet {
|
||||||
@ -48,7 +49,10 @@ export class RdDActorSheet extends ActorSheet {
|
|||||||
item => item.data.categorie,
|
item => item.data.categorie,
|
||||||
item => {
|
item => {
|
||||||
let archetypeKey = (item.data.niveau_archetype < 0) ? 0 : item.data.niveau_archetype;
|
let archetypeKey = (item.data.niveau_archetype < 0) ? 0 : item.data.niveau_archetype;
|
||||||
data.data.comptageArchetype[archetypeKey].nombre = data.data.comptageArchetype[archetypeKey].nombre + 1; //Comptage archetype
|
if (data.data.comptageArchetype[archetypeKey] == undefined) {
|
||||||
|
data.data.comptageArchetype[archetypeKey] = { "niveau": archetypeKey, "nombreMax": 0, "nombre": 0};
|
||||||
|
}
|
||||||
|
data.data.comptageArchetype[archetypeKey].nombre = (data.data.comptageArchetype[archetypeKey]?.nombre??0) + 1; //Comptage archetype
|
||||||
item.data.xpNext = RdDItemCompetence.getCompetenceNextXp(item.data.niveau);
|
item.data.xpNext = RdDItemCompetence.getCompetenceNextXp(item.data.niveau);
|
||||||
item.data.isLevelUp = item.data.xp >= item.data.xpNext; // Flag de niveau à MAJ
|
item.data.isLevelUp = item.data.xp >= item.data.xpNext; // Flag de niveau à MAJ
|
||||||
//this.actor.checkCompetenceXP(item.name); // Petite vérification experience
|
//this.actor.checkCompetenceXP(item.name); // Petite vérification experience
|
||||||
@ -92,12 +96,12 @@ export class RdDActorSheet extends ActorSheet {
|
|||||||
|
|
||||||
// To avoid armour and so on...
|
// To avoid armour and so on...
|
||||||
data.data.combat = duplicate(RdDUtility.checkNull(data.itemsByType['arme']));
|
data.data.combat = duplicate(RdDUtility.checkNull(data.itemsByType['arme']));
|
||||||
data.data.combat = RdDUtility._finalizeArmeList(data.data.combat, data.itemsByType.competence, data.data.carac);
|
data.data.combat = RdDCombatManager.finalizeArmeList(data.data.combat, data.itemsByType.competence, data.data.carac);
|
||||||
|
|
||||||
data.esquive = { name: "Esquive", niveau: data.competenceByCategory?.melee.find(it => it.name == 'Esquive')?.data.niveau ?? -6};
|
data.esquive = { name: "Esquive", niveau: data.competenceByCategory?.melee.find(it => it.name == 'Esquive')?.data.niveau ?? -6};
|
||||||
let corpsACorps = data.competenceByCategory?.melee.find(it => it.name == 'Corps à corps');
|
let corpsACorps = data.competenceByCategory?.melee.find(it => it.name == 'Corps à corps');
|
||||||
if (corpsACorps) {
|
if (corpsACorps) {
|
||||||
let cc_init = RdDUtility.calculInitiative(corpsACorps.data.niveau, data.data.carac['melee'].value);
|
let cc_init = RdDCombatManager.calculInitiative(corpsACorps.data.niveau, data.data.carac['melee'].value);
|
||||||
data.data.combat.push(RdDItemArme.mainsNues({ niveau: corpsACorps.data.niveau, initiative: cc_init }));
|
data.data.combat.push(RdDItemArme.mainsNues({ niveau: corpsACorps.data.niveau, initiative: cc_init }));
|
||||||
}
|
}
|
||||||
this.armesList = duplicate(data.data.combat);
|
this.armesList = duplicate(data.data.combat);
|
||||||
@ -354,7 +358,7 @@ export class RdDActorSheet extends ActorSheet {
|
|||||||
if (combatant) {
|
if (combatant) {
|
||||||
let armeName = event.currentTarget.attributes['data-arme-name'].value;
|
let armeName = event.currentTarget.attributes['data-arme-name'].value;
|
||||||
let arme = this.armesList.find(a => a.name == armeName);
|
let arme = this.armesList.find(a => a.name == armeName);
|
||||||
RdDUtility.rollInitiativeCompetence(combatant._id, arme);
|
RdDCombatManager.rollInitiativeCompetence(combatant._id, arme);
|
||||||
} else {
|
} else {
|
||||||
ui.notifications.info("Impossible de lancer l'initiative sans être dans un combat.");
|
ui.notifications.info("Impossible de lancer l'initiative sans être dans un combat.");
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
|
|
||||||
const articlesApostrophes = {
|
const articlesApostrophes = {
|
||||||
'de' : 'd\'',
|
'de': 'd\'',
|
||||||
'le' : 'l\'',
|
'le': 'l\'',
|
||||||
'la' : 'l\''
|
'la': 'l\''
|
||||||
}
|
}
|
||||||
export class Grammar {
|
export class Grammar {
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
static apostrophe(article, word) {
|
static apostrophe(article, word) {
|
||||||
if (articlesApostrophes[article] && Grammar.startsWithVoyel(word)) {
|
if (articlesApostrophes[article] && Grammar.startsWithVoyel(word)) {
|
||||||
return articlesApostrophes[article] + word
|
return articlesApostrophes[article] + word
|
||||||
@ -13,28 +14,58 @@ export class Grammar {
|
|||||||
return article + ' ' + word;
|
return article + ' ' + word;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
static startsWithVoyel(word) {
|
static startsWithVoyel(word) {
|
||||||
return word.match(/^[aeiouy]/i)
|
return word.match(/^[aeiouy]/i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
static toLowerCaseNoAccent(words) {
|
static toLowerCaseNoAccent(words) {
|
||||||
return words?.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "") ?? words;
|
return words?.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "") ?? words;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
static articleDetermine(genre) {
|
static articleDetermine(genre) {
|
||||||
switch (genre?.toLowerCase()) {
|
switch (toLowerCaseNoAccent(genre)) {
|
||||||
case 'f': case 'feminin': return 'la';
|
case 'f': case 'feminin': return 'la';
|
||||||
case 'p': case 'pluriel': return 'les';
|
case 'p': case 'mp': case 'fp': case 'pluriel': return 'les';
|
||||||
default:
|
default:
|
||||||
case 'm': case 'masculin': return 'le';
|
case 'm': case 'masculin': return 'le';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
static articleIndétermine(genre) {
|
static articleIndétermine(genre) {
|
||||||
switch (genre?.toLowerCase()) {
|
switch (toLowerCaseNoAccent(genre)) {
|
||||||
case 'f': case 'feminin': return 'une';
|
case 'f': case 'feminin': return 'une';
|
||||||
case 'p': case 'pluriel': return 'des';
|
case 'p': case 'fp': case 'mp': case 'pluriel': return 'des';
|
||||||
case 'n': case 'neutre': return 'du'
|
case 'n': case 'neutre': return 'du'
|
||||||
default:
|
default:
|
||||||
case 'm': case 'masculin': return 'un';
|
case 'm': case 'masculin': return 'un';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/**
|
||||||
|
* renvoie un des mots en fonction du genre:
|
||||||
|
*
|
||||||
|
* - masculin/neutre/m/n : mots[0]
|
||||||
|
* - feminin/f : mots[1]
|
||||||
|
* - pluriel/mp/p : mots[2]
|
||||||
|
* - fp : mots[3]
|
||||||
|
*
|
||||||
|
* @param {*} genre
|
||||||
|
* @param {...any} mots
|
||||||
|
*/
|
||||||
|
static accord(genre, ...mots) {
|
||||||
|
switch (toLowerCaseNoAccent(genre)) {
|
||||||
|
default:
|
||||||
|
case 'n': case 'neutre':
|
||||||
|
case 'm': case 'masculin': return mots[0];
|
||||||
|
case 'f': case 'feminin': return mots[1];
|
||||||
|
case 'p': case 'mp': case 'pluriel': return mots[2]
|
||||||
|
case 'fp': return mots[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -145,7 +145,7 @@ export class RdDItemArme extends Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static isArmeUtilisable(item) {
|
static isArmeUtilisable(item) {
|
||||||
return item.type == 'arme' && item.data.resistance > 0;
|
return item.type == 'arme' && (item.data.resistance > 0 || item.data.portee_courte>0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static mainsNues(actorData={}) {
|
static mainsNues(actorData={}) {
|
||||||
|
@ -12,17 +12,24 @@ import { ReglesOptionelles } from "./regles-optionelles.js";
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
export class RdDCombatManager extends Combat {
|
export class RdDCombatManager extends Combat {
|
||||||
|
|
||||||
|
static init() {
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
Hooks.on("getCombatTrackerEntryContext", (html, options) => {
|
||||||
|
RdDCombatManager.pushInitiativeOptions(html, options);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
cleanItemUse() {
|
cleanItemUse() {
|
||||||
for(let turn of this.turns) {
|
for (let turn of this.turns) {
|
||||||
turn.actor.resetItemUse()
|
turn.actor.resetItemUse()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
cleanSonne( ) {
|
cleanSonne() {
|
||||||
for (let combatant of this.data.combatants) {
|
for (let combatant of this.data.combatants) {
|
||||||
combatant.actor.verifierSonneRound( this.current.round );
|
combatant.actor.verifierSonneRound(this.current.round);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,7 +38,268 @@ export class RdDCombatManager extends Combat {
|
|||||||
//console.log('New round !');s
|
//console.log('New round !');s
|
||||||
this.cleanItemUse();
|
this.cleanItemUse();
|
||||||
this.cleanSonne();
|
this.cleanSonne();
|
||||||
|
return super.nextRound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/************************************************************************************/
|
||||||
|
async rollInitiative(ids, formula = undefined, messageOptions = {}) {
|
||||||
|
console.log(`${game.data.system.data.title} | Combat.rollInitiative()`, ids, formula, messageOptions);
|
||||||
|
// Structure input data
|
||||||
|
ids = typeof ids === "string" ? [ids] : ids;
|
||||||
|
const currentId = this.combatant._id;
|
||||||
|
// calculate initiative
|
||||||
|
for (let cId = 0; cId < ids.length; cId++) {
|
||||||
|
const c = this.getCombatant(ids[cId]);
|
||||||
|
//if (!c) return results;
|
||||||
|
|
||||||
|
let rollFormula = formula; // Init per default
|
||||||
|
if (!rollFormula) {
|
||||||
|
let armeCombat, competence;
|
||||||
|
if (c.actor.data.type == 'creature' || c.actor.data.type == 'entite') {
|
||||||
|
for (const competenceItem of c.actor.data.items) {
|
||||||
|
if (competenceItem.data.iscombat) {
|
||||||
|
competence = duplicate(competenceItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rollFormula = "2+( (" + RdDCombatManager.calculInitiative(competence.data.niveau, competence.data.carac_value) + ")/100)";
|
||||||
|
} else {
|
||||||
|
for (const item of c.actor.data.items) {
|
||||||
|
if (item.type == "arme" && item.data.equipe) {
|
||||||
|
armeCombat = duplicate(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let compName = (armeCombat == undefined) ? "Corps à corps" : armeCombat.data.competence;
|
||||||
|
competence = RdDItemCompetence.findCompetence(c.actor.data.items, compName);
|
||||||
|
let bonusEcaille = (armeCombat && armeCombat.data.magique) ? armeCombat.data.ecaille_efficacite : 0;
|
||||||
|
rollFormula = "2+( (" + RdDCombatManager.calculInitiative(competence.data.niveau, c.actor.data.data.carac[competence.data.defaut_carac].value, bonusEcaille) + ")/100)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//console.log("Combatat", c);
|
||||||
|
const roll = super._getInitiativeRoll(c, rollFormula);
|
||||||
|
if (roll.total <= 0) roll.total = 0.00;
|
||||||
|
console.log("Compute init for", rollFormula, roll.total);
|
||||||
|
await this.updateEmbeddedEntity("Combatant", { _id: c._id, initiative: roll.total });
|
||||||
|
|
||||||
|
// Send a chat message
|
||||||
|
let rollMode = messageOptions.rollMode || game.settings.get("core", "rollMode");
|
||||||
|
let messageData = mergeObject(
|
||||||
|
{
|
||||||
|
speaker: {
|
||||||
|
scene: canvas.scene._id,
|
||||||
|
actor: c.actor ? c.actor._id : null,
|
||||||
|
token: c.token._id,
|
||||||
|
alias: c.token.name,
|
||||||
|
sound: CONFIG.sounds.dice,
|
||||||
|
},
|
||||||
|
flavor: `${c.token.name} a fait son jet d'Initiative (${messageOptions.initInfo})
|
||||||
|
<br>
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
messageOptions
|
||||||
|
);
|
||||||
|
roll.toMessage(messageData, { rollMode, create: true });
|
||||||
|
|
||||||
|
RdDCombatManager.processPremierRoundInit();
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
static calculInitiative(niveau, caracValue, bonusEcaille = 0) {
|
||||||
|
let base = niveau + Math.floor(caracValue / 2);
|
||||||
|
base += bonusEcaille;
|
||||||
|
return "1d6" + (base >= 0 ? "+" : "") + base;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/** Retourne une liste triée d'armes avec le split arme1 main / arme 2 main */
|
||||||
|
static finalizeArmeList(armes, competences, carac) {
|
||||||
|
// Gestion des armes 1/2 mains
|
||||||
|
let armesEquipe = [];
|
||||||
|
for (const arme of armes) {
|
||||||
|
if (arme.data.equipe) {
|
||||||
|
armesEquipe.push(arme);
|
||||||
|
let comp = competences.find(c => c.name == arme.data.competence);
|
||||||
|
arme.data.initiative = RdDCombatManager.calculInitiative(arme.data.niveau, carac[comp.data.defaut_carac].value);
|
||||||
|
// Dupliquer les armes pouvant être à 1 main et 2 mains en patchant la compétence
|
||||||
|
if (arme.data.unemain && !arme.data.deuxmains) {
|
||||||
|
arme.data.mainInfo = "(1m)";
|
||||||
|
} else if (!arme.data.unemain && arme.data.deuxmains) {
|
||||||
|
arme.data.mainInfo = "(2m)";
|
||||||
|
} else if (arme.data.unemain && arme.data.deuxmains) {
|
||||||
|
arme.data.mainInfo = "(1m)";
|
||||||
|
let arme2main = duplicate(arme);
|
||||||
|
arme2main.data.mainInfo = "(2m)";
|
||||||
|
arme2main.data.dommages = arme2main.data.dommages.split("/")[1]; // Existence temporaire uniquement dans la liste des armes, donc OK
|
||||||
|
arme2main.data.competence = arme2main.data.competence.replace(" 1 main", " 2 mains"); // Replace !
|
||||||
|
let comp = competences.find(c => c.name == arme2main.data.competence);
|
||||||
|
arme2main.data.niveau = comp.data.niveau;
|
||||||
|
arme2main.data.initiative = RdDCombatManager.calculInitiative(arme2main.data.niveau, carac[comp.data.defaut_carac].value);
|
||||||
|
armesEquipe.push(arme2main);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return armesEquipe.sort((a, b) => {
|
||||||
|
const nameA = a.name + (a.data.mainInfo ?? '');
|
||||||
|
const nameB = b.name + (b.data.mainInfo ?? '');
|
||||||
|
if (nameA > nameB) return 1;
|
||||||
|
if (nameA < nameB) return -1;
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
static buildListeActionsCombat(combatant) {
|
||||||
|
const actor = combatant.actor; // Easy access
|
||||||
|
let items = actor.data.items;
|
||||||
|
let actions = []
|
||||||
|
if (actor.isCreature()) {
|
||||||
|
actions = actions.concat(items.filter(it => RdDItemCompetenceCreature.isCompetenceAttaque(it))
|
||||||
|
.map(competence => RdDItemCompetenceCreature.toArme(competence)));
|
||||||
|
} else {
|
||||||
|
// Recupération des items 'arme'
|
||||||
|
let armes = items.filter(it => RdDItemArme.isArmeUtilisable(it))
|
||||||
|
.map(arme => duplicate(arme)) /* pas de changements aux armes d'origine */
|
||||||
|
.concat(RdDItemArme.mainsNues());
|
||||||
|
|
||||||
|
let competences = items.filter(it => it.type == 'competence');
|
||||||
|
actions = actions.concat(RdDCombatManager.finalizeArmeList(armes, competences, actor.data.data.carac));
|
||||||
|
|
||||||
|
actions.push({ name: "Draconic", data: { initOnly: true, competence: "Draconic" } });
|
||||||
|
}
|
||||||
|
|
||||||
|
actions.push({ name: "Autre action", data: { initOnly: true, competence: "Autre action" } });
|
||||||
|
for (let index = 0; index < actions.length; index++) {
|
||||||
|
actions[index].index = index;
|
||||||
|
}
|
||||||
|
return actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
static processPremierRoundInit() {
|
||||||
|
// Check if we have the whole init !
|
||||||
|
if (game.user.isGM && game.combat.current.round == 1) {
|
||||||
|
let initMissing = game.combat.data.combatants.find(it => !it.initiative);
|
||||||
|
if (!initMissing) { // Premier round !
|
||||||
|
for (let combatant of game.combat.data.combatants) {
|
||||||
|
let arme = combatant.initiativeData?.arme;
|
||||||
|
//console.log("Parsed !!!", combatant, initDone, game.combat.current, arme);
|
||||||
|
if (arme && arme.type == "arme") {
|
||||||
|
for (let initData of premierRoundInit) {
|
||||||
|
if (arme.data.initpremierround.toLowerCase().includes(initData.pattern)) {
|
||||||
|
let msg = `<h4>L'initiative de ${combatant.actor.name} a été modifiée !</h4>
|
||||||
|
<hr>
|
||||||
|
<div>
|
||||||
|
Etant donné son ${arme.name}, son initative pour ce premier round est désormais de ${initData.init}.
|
||||||
|
</div>`
|
||||||
|
ChatMessage.create({ content: msg });
|
||||||
|
game.combat.setInitiative(combatant._id, initData.init);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
static incDecInit(combatantId, incDecValue) {
|
||||||
|
const combatant = game.combat.getCombatant(combatantId);
|
||||||
|
let initValue = combatant.initiative + incDecValue;
|
||||||
|
game.combat.setInitiative(combatantId, initValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
static pushInitiativeOptions(html, options) {
|
||||||
|
for (let i = 0; i < options.length; i++) {
|
||||||
|
let option = options[i];
|
||||||
|
if (option.name == 'COMBAT.CombatantReroll') { // Replace !
|
||||||
|
option.name = "Sélectionner l'initiative...";
|
||||||
|
option.condition = true;
|
||||||
|
option.icon = '<i class="far fa-question-circle"></i>';
|
||||||
|
option.callback = target => {
|
||||||
|
RdDCombatManager.displayInitiativeMenu(html, target.data('combatant-id'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
options = [
|
||||||
|
{ name: "Incrémenter initiative", condition: true, icon: '<i class="fas fa-plus"></i>', callback: target => { RdDCombatManager.incDecInit(target.data('combatant-id'), +0.01); } },
|
||||||
|
{ name: "Décrémenter initiative", condition: true, icon: '<i class="fas fa-minus"></i>', callback: target => { RdDCombatManager.incDecInit(target.data('combatant-id'), -0.01); } }
|
||||||
|
].concat(options);
|
||||||
|
}
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
static rollInitiativeCompetence(combatantId, arme) {
|
||||||
|
const combatant = game.combat.getCombatant(combatantId);
|
||||||
|
const actor = combatant.actor;
|
||||||
|
|
||||||
|
let initInfo = "";
|
||||||
|
let initOffset = 0;
|
||||||
|
let caracForInit = 0;
|
||||||
|
let compNiveau = 0;
|
||||||
|
let competence = { name: "Aucune" };
|
||||||
|
if (actor.getSurprise() == "totale") {
|
||||||
|
initOffset = -1; // To force 0
|
||||||
|
initInfo = "Surprise Totale"
|
||||||
|
} else if (actor.getSurprise() == "demi") {
|
||||||
|
initOffset = 0;
|
||||||
|
initInfo = "Demi Surprise"
|
||||||
|
} else if (arme.name == "Autre action") {
|
||||||
|
initOffset = 2;
|
||||||
|
initInfo = "Autre Action"
|
||||||
|
} else if (arme.name == "Draconic") {
|
||||||
|
initOffset = 7;
|
||||||
|
initInfo = "Draconic"
|
||||||
|
} else {
|
||||||
|
initOffset = 3; // Melée = 3.XX
|
||||||
|
competence = RdDItemCompetence.findCompetence(combatant.actor.data.items, arme.data.competence);
|
||||||
|
compNiveau = competence.data.niveau;
|
||||||
|
initInfo = arme.name + " / " + arme.data.competence;
|
||||||
|
|
||||||
|
if (actor.data.type == 'creature' || actor.data.type == 'entite') {
|
||||||
|
caracForInit = competence.data.carac_value;
|
||||||
|
if (competence.data.categorie == "lancer") {
|
||||||
|
initOffset = 5;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
caracForInit = actor.data.data.carac[competence.data.defaut_carac].value;
|
||||||
|
if (competence.data.categorie == "lancer") { // Offset de principe pour les armes de jet
|
||||||
|
initOffset = 4;
|
||||||
|
}
|
||||||
|
if (competence.data.categorie == "tir") { // Offset de principe pour les armes de jet
|
||||||
|
initOffset = 5;
|
||||||
|
}
|
||||||
|
if (competence.data.categorie == "melee") { // Offset de principe pour les armes de jet
|
||||||
|
initOffset = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let malus = actor.getEtatGeneral(); // Prise en compte état général
|
||||||
|
// Cas des créatures et entités vs personnages
|
||||||
|
let rollFormula = initOffset + "+ ( (" + RdDCombatManager.calculInitiative(compNiveau, caracForInit) + " + " + malus + ") /100)";
|
||||||
|
// Garder la trace de l'arme/compétence utilisée pour l'iniative
|
||||||
|
combatant.initiativeData = { arme: arme } // pour reclasser l'init au round 0
|
||||||
|
game.combat.rollInitiative(combatantId, rollFormula, { initInfo: initInfo });
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
static displayInitiativeMenu(html, combatantId) {
|
||||||
|
const combatant = game.combat.getCombatant(combatantId);
|
||||||
|
let armesList = RdDCombatManager.buildListeActionsCombat(combatant);
|
||||||
|
|
||||||
|
// Build the relevant submenu
|
||||||
|
if (armesList) {
|
||||||
|
let menuItems = [];
|
||||||
|
for (let arme of armesList) {
|
||||||
|
menuItems.push({
|
||||||
|
name: arme.data.competence,
|
||||||
|
icon: "<i class='fas fa-dice-d6'></i>",
|
||||||
|
callback: target => { RdDCombatManager.rollInitiativeCompetence(combatantId, arme) }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
new ContextMenu(html, ".directory-list", menuItems).render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@ -384,8 +652,8 @@ export class RdDCombat {
|
|||||||
|
|
||||||
let rollData = this._prepareAttaque(competence, arme);
|
let rollData = this._prepareAttaque(competence, arme);
|
||||||
console.log("RdDCombat.attaque >>>", rollData);
|
console.log("RdDCombat.attaque >>>", rollData);
|
||||||
this.attacker.incItemUse( arme._id ); // Usage
|
this.attacker.incItemUse(arme._id); // Usage
|
||||||
this.attacker.verifierForceMin( arme );
|
this.attacker.verifierForceMin(arme);
|
||||||
|
|
||||||
const dialog = await RdDRoll.create(this.attacker, rollData,
|
const dialog = await RdDRoll.create(this.attacker, rollData,
|
||||||
{
|
{
|
||||||
@ -490,7 +758,7 @@ export class RdDCombat {
|
|||||||
let esquiveUsage = 0;
|
let esquiveUsage = 0;
|
||||||
let esquive = this.defender.getCompetence("esquive");
|
let esquive = this.defender.getCompetence("esquive");
|
||||||
if (esquive) {
|
if (esquive) {
|
||||||
esquiveUsage = this.defender.getItemUse( esquive._id);
|
esquiveUsage = this.defender.getItemUse(esquive._id);
|
||||||
}
|
}
|
||||||
|
|
||||||
const paramChatDefense = {
|
const paramChatDefense = {
|
||||||
@ -550,8 +818,8 @@ export class RdDCombat {
|
|||||||
_filterArmesParade(defender, competence) {
|
_filterArmesParade(defender, competence) {
|
||||||
let items = defender.data.items;
|
let items = defender.data.items;
|
||||||
items = items.filter(item => RdDItemArme.isArmeUtilisable(item) || RdDItemCompetenceCreature.isCompetenceParade(item));
|
items = items.filter(item => RdDItemArme.isArmeUtilisable(item) || RdDItemCompetenceCreature.isCompetenceParade(item));
|
||||||
for( let item of items) {
|
for (let item of items) {
|
||||||
item.data.nbUsage = defender.getItemUse( item._id); // Ajout du # d'utilisation ce round
|
item.data.nbUsage = defender.getItemUse(item._id); // Ajout du # d'utilisation ce round
|
||||||
}
|
}
|
||||||
switch (competence.data.categorie) {
|
switch (competence.data.categorie) {
|
||||||
case 'tir':
|
case 'tir':
|
||||||
@ -571,9 +839,8 @@ export class RdDCombat {
|
|||||||
|
|
||||||
RdDCombat._storeAttaque(this.attackerId, attackerRoll);
|
RdDCombat._storeAttaque(this.attackerId, attackerRoll);
|
||||||
|
|
||||||
// Finesse et Rapidité seulement en mêlée et si la difficulté libre est de -1 minimum
|
|
||||||
ChatMessage.create({
|
ChatMessage.create({
|
||||||
whisper: ChatMessage.getWhisperRecipients(this.attacker.name),
|
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.attacker.name),
|
||||||
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-etotal.html', {
|
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-etotal.html', {
|
||||||
attackerId: this.attackerId,
|
attackerId: this.attackerId,
|
||||||
attacker: this.attacker,
|
attacker: this.attacker,
|
||||||
@ -591,7 +858,7 @@ export class RdDCombat {
|
|||||||
const avecArme = arme?.data.categorie_parade != 'sans-armes';
|
const avecArme = arme?.data.categorie_parade != 'sans-armes';
|
||||||
const action = (rollData.attackerRoll ? (arme ? "la parade" : "l'esquive") : "l'attaque");
|
const action = (rollData.attackerRoll ? (arme ? "la parade" : "l'esquive") : "l'attaque");
|
||||||
ChatUtility.createChatWithRollMode(this.defender.name, {
|
ChatUtility.createChatWithRollMode(this.defender.name, {
|
||||||
content: `<strong>Echec total à ${action}!</strong> ` + await RdDRollTables.getMaladresse({ arme: avecArme })
|
content: `<strong>Maladresse à ${action}!</strong> ` + await RdDRollTables.getMaladresse({ arme: avecArme })
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -616,7 +883,7 @@ export class RdDCombat {
|
|||||||
let arme = this.defender.getArmeParade(armeParadeId);
|
let arme = this.defender.getArmeParade(armeParadeId);
|
||||||
|
|
||||||
console.log("RdDCombat.parade >>>", attackerRoll, armeParadeId, arme);
|
console.log("RdDCombat.parade >>>", attackerRoll, armeParadeId, arme);
|
||||||
this.defender.incItemUse( armeParadeId ); // Usage
|
this.defender.incItemUse(armeParadeId); // Usage
|
||||||
|
|
||||||
let rollData = this._prepareParade(attackerRoll, arme);
|
let rollData = this._prepareParade(attackerRoll, arme);
|
||||||
|
|
||||||
@ -724,7 +991,7 @@ export class RdDCombat {
|
|||||||
}
|
}
|
||||||
console.log("RdDCombat.esquive >>>", attackerRoll, esquive);
|
console.log("RdDCombat.esquive >>>", attackerRoll, esquive);
|
||||||
let rollData = this._prepareEsquive(attackerRoll, esquive);
|
let rollData = this._prepareEsquive(attackerRoll, esquive);
|
||||||
this.defender.incItemUse( esquive._id ); // Usage
|
this.defender.incItemUse(esquive._id); // Usage
|
||||||
|
|
||||||
const dialog = await RdDRoll.create(this.defender, rollData,
|
const dialog = await RdDRoll.create(this.defender, rollData,
|
||||||
{ html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-competence.html' }, {
|
{ html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-competence.html' }, {
|
||||||
@ -803,10 +1070,10 @@ export class RdDCombat {
|
|||||||
const dmg = attackerRoll.dmg.dmgArme + attackerRoll.dmg.dmgActor;
|
const dmg = attackerRoll.dmg.dmgArme + attackerRoll.dmg.dmgActor;
|
||||||
let arme = defenderRoll.arme;
|
let arme = defenderRoll.arme;
|
||||||
let msg = "";
|
let msg = "";
|
||||||
if ( arme.data.magique ) {
|
if (arme.data.magique) {
|
||||||
defenderRoll.show.deteriorationArme = 'resiste'; // Par défaut
|
defenderRoll.show.deteriorationArme = 'resiste'; // Par défaut
|
||||||
if (arme.data.resistance_magique == undefined) arme.data.resistance_magique = 0; // Quick fix
|
if (arme.data.resistance_magique == undefined) arme.data.resistance_magique = 0; // Quick fix
|
||||||
if ( dmg > arme.data.resistance_magique) { // Jet uniquement si dommages supérieur à résistance magique (cf. 274)
|
if (dmg > arme.data.resistance_magique) { // Jet uniquement si dommages supérieur à résistance magique (cf. 274)
|
||||||
let resistance = Misc.toInt(arme.data.resistance);
|
let resistance = Misc.toInt(arme.data.resistance);
|
||||||
// Jet de résistance de l'arme de parade (p.132)
|
// Jet de résistance de l'arme de parade (p.132)
|
||||||
let resistRoll = await RdDResolutionTable.rollData({
|
let resistRoll = await RdDResolutionTable.rollData({
|
||||||
@ -814,10 +1081,10 @@ export class RdDCombat {
|
|||||||
finalLevel: - dmg,
|
finalLevel: - dmg,
|
||||||
showDice: false
|
showDice: false
|
||||||
});
|
});
|
||||||
if ( !resistRoll.rolled.isSuccess) {
|
if (!resistRoll.rolled.isSuccess) {
|
||||||
let perteResistance = ( dmg - arme.data.resistance_magique)
|
let perteResistance = (dmg - arme.data.resistance_magique)
|
||||||
resistance -= perteResistance;
|
resistance -= perteResistance;
|
||||||
defenderRoll.show.deteriorationArme = resistance <= 0 ? 'brise': 'perte';
|
defenderRoll.show.deteriorationArme = resistance <= 0 ? 'brise' : 'perte';
|
||||||
defenderRoll.show.perteResistance = perteResistance;
|
defenderRoll.show.perteResistance = perteResistance;
|
||||||
this.defender.updateEmbeddedEntity("OwnedItem", { _id: defenderRoll.arme._id, 'data.resistance': resistance });
|
this.defender.updateEmbeddedEntity("OwnedItem", { _id: defenderRoll.arme._id, 'data.resistance': resistance });
|
||||||
}
|
}
|
||||||
@ -834,7 +1101,7 @@ export class RdDCombat {
|
|||||||
defenderRoll.show.deteriorationArme = 'resiste';
|
defenderRoll.show.deteriorationArme = 'resiste';
|
||||||
} else {
|
} else {
|
||||||
resistance -= dmg;
|
resistance -= dmg;
|
||||||
defenderRoll.show.deteriorationArme = resistance <= 0 ? 'brise': 'perte';
|
defenderRoll.show.deteriorationArme = resistance <= 0 ? 'brise' : 'perte';
|
||||||
defenderRoll.show.perteResistance = dmg;
|
defenderRoll.show.perteResistance = dmg;
|
||||||
this.defender.updateEmbeddedEntity("OwnedItem", { _id: defenderRoll.arme._id, 'data.resistance': resistance });
|
this.defender.updateEmbeddedEntity("OwnedItem", { _id: defenderRoll.arme._id, 'data.resistance': resistance });
|
||||||
}
|
}
|
||||||
|
@ -34,77 +34,7 @@ import { EffetsDraconiques } from "./tmr/effets-draconiques.js";
|
|||||||
/* Foundry VTT Initialization */
|
/* Foundry VTT Initialization */
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/************************************************************************************/
|
|
||||||
const _patch_initiative = () => {
|
|
||||||
Combat.prototype.rollInitiative = async function (
|
|
||||||
ids,
|
|
||||||
formula = undefined,
|
|
||||||
messageOptions = {}
|
|
||||||
) {
|
|
||||||
console.log(
|
|
||||||
`${game.data.system.data.title} | Combat.rollInitiative()`,
|
|
||||||
ids,
|
|
||||||
formula,
|
|
||||||
messageOptions
|
|
||||||
);
|
|
||||||
// Structure input data
|
|
||||||
ids = typeof ids === "string" ? [ids] : ids;
|
|
||||||
const currentId = this.combatant._id;
|
|
||||||
// calculate initiative
|
|
||||||
for (let cId = 0; cId < ids.length; cId++) {
|
|
||||||
const c = this.getCombatant(ids[cId]);
|
|
||||||
//if (!c) return results;
|
|
||||||
|
|
||||||
let rollFormula = formula; // Init per default
|
|
||||||
if (!rollFormula) {
|
|
||||||
let armeCombat, competence;
|
|
||||||
if (c.actor.data.type == 'creature' || c.actor.data.type == 'entite') {
|
|
||||||
for (const competenceItem of c.actor.data.items) {
|
|
||||||
if (competenceItem.data.iscombat) {
|
|
||||||
competence = duplicate(competenceItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rollFormula = "2+( ("+RdDUtility.calculInitiative(competence.data.niveau, competence.data.carac_value)+")/100)";
|
|
||||||
} else {
|
|
||||||
for (const item of c.actor.data.items) {
|
|
||||||
if (item.type == "arme" && item.data.equipe) {
|
|
||||||
armeCombat = duplicate(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let compName = (armeCombat == undefined) ? "Corps à corps" : armeCombat.data.competence;
|
|
||||||
competence = RdDItemCompetence.findCompetence(c.actor.data.items, compName);
|
|
||||||
let bonusEcaille = (armeCombat && armeCombat.data.magique) ? armeCombat.data.ecaille_efficacite : 0;
|
|
||||||
rollFormula = "2+( ("+RdDUtility.calculInitiative(competence.data.niveau, c.actor.data.data.carac[competence.data.defaut_carac].value, bonusEcaille) + ")/100)";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//console.log("Combatat", c);
|
|
||||||
const roll = this._getInitiativeRoll(c, rollFormula);
|
|
||||||
if (roll.total <= 0) roll.total = 0.00;
|
|
||||||
console.log("Compute init for", rollFormula, roll.total);
|
|
||||||
await this.updateEmbeddedEntity("Combatant", { _id: c._id, initiative: roll.total });
|
|
||||||
|
|
||||||
// Send a chat message
|
|
||||||
let rollMode = messageOptions.rollMode || game.settings.get("core", "rollMode");
|
|
||||||
let messageData = mergeObject(
|
|
||||||
{
|
|
||||||
speaker: {
|
|
||||||
scene: canvas.scene._id,
|
|
||||||
actor: c.actor ? c.actor._id : null,
|
|
||||||
token: c.token._id,
|
|
||||||
alias: c.token.name,
|
|
||||||
sound: CONFIG.sounds.dice,
|
|
||||||
},
|
|
||||||
flavor: `${c.token.name} a fait son jet d'Initiative (${messageOptions.initInfo})`,
|
|
||||||
},
|
|
||||||
messageOptions
|
|
||||||
);
|
|
||||||
roll.toMessage(messageData, { rollMode, create: true });
|
|
||||||
|
|
||||||
RdDUtility.processPremierRoundInit( );
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/************************************************************************************/
|
/************************************************************************************/
|
||||||
Hooks.once("init", async function () {
|
Hooks.once("init", async function () {
|
||||||
@ -222,15 +152,10 @@ Hooks.once("init", async function () {
|
|||||||
Items.registerSheet("foundryvtt-reve-de-dragon", RdDItemSheet, { makeDefault: true });
|
Items.registerSheet("foundryvtt-reve-de-dragon", RdDItemSheet, { makeDefault: true });
|
||||||
CONFIG.Combat.entityClass = RdDCombatManager;
|
CONFIG.Combat.entityClass = RdDCombatManager;
|
||||||
|
|
||||||
// Handlebar function pour container
|
|
||||||
Handlebars.registerHelper('buildConteneur', (objet) => { return RdDUtility.buildConteneur(objet); });
|
|
||||||
|
|
||||||
// Patch the initiative formula
|
|
||||||
_patch_initiative();
|
|
||||||
|
|
||||||
// préparation des différents modules
|
// préparation des différents modules
|
||||||
RdDCommands.init();
|
RdDCommands.init();
|
||||||
RdDCombat.init();
|
RdDCombat.init();
|
||||||
|
RdDCombatManager.init(),
|
||||||
RdDTokenHud.init();
|
RdDTokenHud.init();
|
||||||
RdDActor.init();
|
RdDActor.init();
|
||||||
RddCompendiumOrganiser.init();
|
RddCompendiumOrganiser.init();
|
||||||
@ -299,10 +224,6 @@ Hooks.on("chatMessage", (html, content, msg) => {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
Hooks.on("getCombatTrackerEntryContext", (html, options) => {
|
|
||||||
RdDUtility.pushInitiativeOptions(html, options);
|
|
||||||
});
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
Hooks.on("renderChatMessage", async (app, html, msg) => {
|
Hooks.on("renderChatMessage", async (app, html, msg) => {
|
||||||
|
@ -125,7 +125,7 @@ export class RdDResolutionTable {
|
|||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static _updateChancesFactor(chances, diviseur) {
|
static _updateChancesFactor(chances, diviseur) {
|
||||||
if (diviseur && diviseur > 1) {
|
if (chances.level > -11 && diviseur && diviseur > 1) {
|
||||||
let newScore = Math.floor(chances.score / diviseur);
|
let newScore = Math.floor(chances.score / diviseur);
|
||||||
mergeObject(chances, this._computeCell(null, newScore), { overwrite: true });
|
mergeObject(chances, this._computeCell(null, newScore), { overwrite: true });
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
import { HtmlUtility } from "./html-utility.js";
|
import { HtmlUtility } from "./html-utility.js";
|
||||||
|
import { RdDCombatManager } from "./rdd-combat.js";
|
||||||
import { RdDUtility } from "./rdd-utility.js";
|
import { RdDUtility } from "./rdd-utility.js";
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@ -26,7 +27,7 @@ export class RdDTokenHud {
|
|||||||
let combatant = game.combat.data.combatants.find(c => c.tokenId == token.data._id);
|
let combatant = game.combat.data.combatants.find(c => c.tokenId == token.data._id);
|
||||||
app.hasExtension = true;
|
app.hasExtension = true;
|
||||||
|
|
||||||
let armesList = RdDUtility.buildListeActionsCombat(combatant) ;
|
let armesList = RdDCombatManager.buildListeActionsCombat(combatant) ;
|
||||||
const hudData = { combatant: combatant, armes: armesList,
|
const hudData = { combatant: combatant, armes: armesList,
|
||||||
commandes: [{ name: 'Initiative +1', command: 'inc', value: 0.01}, { name: 'Initiative -1',command: 'dec', value: -0.01}] };
|
commandes: [{ name: 'Initiative +1', command: 'inc', value: 0.01}, { name: 'Initiative -1',command: 'dec', value: -0.01}] };
|
||||||
|
|
||||||
@ -38,11 +39,11 @@ export class RdDTokenHud {
|
|||||||
if ( !initCommand ) {
|
if ( !initCommand ) {
|
||||||
let armeIndex = event.currentTarget.attributes['data-arme-id'].value;
|
let armeIndex = event.currentTarget.attributes['data-arme-id'].value;
|
||||||
let arme = armesList[armeIndex];
|
let arme = armesList[armeIndex];
|
||||||
RdDUtility.rollInitiativeCompetence(combatantId, arme);
|
RdDCombatManager.rollInitiativeCompetence(combatantId, arme);
|
||||||
} else if (initCommand == 'inc') {
|
} else if (initCommand == 'inc') {
|
||||||
RdDUtility.incDecInit( combatantId, 0.01 );
|
RdDCombatManager.incDecInit( combatantId, 0.01 );
|
||||||
} else if ( initCommand == 'dec') {
|
} else if ( initCommand == 'dec') {
|
||||||
RdDUtility.incDecInit( combatantId, -0.01 );
|
RdDCombatManager.incDecInit( combatantId, -0.01 );
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
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 { RdDCombat } from "./rdd-combat.js";
|
import { RdDCombat, RdDCombatManager } from "./rdd-combat.js";
|
||||||
import { RdDRollResolutionTable } from "./rdd-roll-resolution-table.js";
|
import { RdDRollResolutionTable } from "./rdd-roll-resolution-table.js";
|
||||||
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
|
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
|
||||||
import { RdDItemArme } from "./item-arme.js";
|
import { RdDItemArme } from "./item-arme.js";
|
||||||
@ -24,18 +24,18 @@ const categorieCompetences = {
|
|||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
const limitesArchetypes = [
|
const limitesArchetypes = [
|
||||||
{ "niveau": 0, "nombreMax": 100, "nombre":0},
|
{ "niveau": 0, "nombreMax": 100, "nombre": 0 },
|
||||||
{ "niveau": 1, "nombreMax": 10, "nombre":0},
|
{ "niveau": 1, "nombreMax": 10, "nombre": 0 },
|
||||||
{ "niveau": 2, "nombreMax": 9, "nombre":0},
|
{ "niveau": 2, "nombreMax": 9, "nombre": 0 },
|
||||||
{ "niveau": 3, "nombreMax": 8, "nombre":0},
|
{ "niveau": 3, "nombreMax": 8, "nombre": 0 },
|
||||||
{ "niveau": 4, "nombreMax": 7, "nombre":0},
|
{ "niveau": 4, "nombreMax": 7, "nombre": 0 },
|
||||||
{ "niveau": 5, "nombreMax": 6, "nombre":0},
|
{ "niveau": 5, "nombreMax": 6, "nombre": 0 },
|
||||||
{ "niveau": 6, "nombreMax": 5, "nombre":0},
|
{ "niveau": 6, "nombreMax": 5, "nombre": 0 },
|
||||||
{ "niveau": 7, "nombreMax": 4, "nombre":0},
|
{ "niveau": 7, "nombreMax": 4, "nombre": 0 },
|
||||||
{ "niveau": 8, "nombreMax": 3, "nombre":0},
|
{ "niveau": 8, "nombreMax": 3, "nombre": 0 },
|
||||||
{ "niveau": 9, "nombreMax": 2, "nombre":0},
|
{ "niveau": 9, "nombreMax": 2, "nombre": 0 },
|
||||||
{ "niveau": 10, "nombreMax": 1, "nombre":0},
|
{ "niveau": 10, "nombreMax": 1, "nombre": 0 },
|
||||||
{ "niveau": 11, "nombreMax": 1, "nombre":0}
|
{ "niveau": 11, "nombreMax": 1, "nombre": 0 }
|
||||||
];
|
];
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@ -274,12 +274,14 @@ export class RdDUtility {
|
|||||||
Handlebars.registerHelper('upper', str => str?.toUpperCase() ?? 'NULL');
|
Handlebars.registerHelper('upper', str => str?.toUpperCase() ?? 'NULL');
|
||||||
Handlebars.registerHelper('le', str => Grammar.articleDetermine(str));
|
Handlebars.registerHelper('le', str => Grammar.articleDetermine(str));
|
||||||
Handlebars.registerHelper('un', str => Grammar.articleIndetermine(str));
|
Handlebars.registerHelper('un', str => Grammar.articleIndetermine(str));
|
||||||
|
Handlebars.registerHelper('accord', (genre, ...args) => Grammar.accord(genre, args));
|
||||||
|
Handlebars.registerHelper('buildConteneur', (objet) => { return RdDUtility.buildConteneur(objet); });
|
||||||
|
|
||||||
return loadTemplates(templatePaths);
|
return loadTemplates(templatePaths);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static getLimitesArchetypes( ) {
|
static getLimitesArchetypes() {
|
||||||
return duplicate(limitesArchetypes);
|
return duplicate(limitesArchetypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -458,50 +460,6 @@ export class RdDUtility {
|
|||||||
return tableCaracDerivee[targetValue]?.xp ?? 200;
|
return tableCaracDerivee[targetValue]?.xp ?? 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
/** Retourne une liste triée d'armes avec le split arme1 main / arme 2 main */
|
|
||||||
static _finalizeArmeList(armes, competences, carac) {
|
|
||||||
// Gestion des armes 1/2 mains
|
|
||||||
let armesEquipe = [];
|
|
||||||
for (const arme of armes) {
|
|
||||||
if (arme.data.equipe) {
|
|
||||||
armesEquipe.push(arme);
|
|
||||||
let comp = competences.find(c => c.name == arme.data.competence);
|
|
||||||
arme.data.initiative = RdDUtility.calculInitiative(arme.data.niveau, carac[comp.data.defaut_carac].value);
|
|
||||||
// Dupliquer les armes pouvant être à 1 main et 2 mains en patchant la compétence
|
|
||||||
if (arme.data.unemain && !arme.data.deuxmains) {
|
|
||||||
arme.data.mainInfo = "(1m)";
|
|
||||||
} else if (!arme.data.unemain && arme.data.deuxmains) {
|
|
||||||
arme.data.mainInfo = "(2m)";
|
|
||||||
} else if (arme.data.unemain && arme.data.deuxmains) {
|
|
||||||
arme.data.mainInfo = "(1m)";
|
|
||||||
let arme2main = duplicate(arme);
|
|
||||||
arme2main.data.mainInfo = "(2m)";
|
|
||||||
arme2main.data.dommages = arme2main.data.dommages.split("/")[1]; // Existence temporaire uniquement dans la liste des armes, donc OK
|
|
||||||
arme2main.data.competence = arme2main.data.competence.replace(" 1 main", " 2 mains"); // Replace !
|
|
||||||
let comp = competences.find(c => c.name == arme2main.data.competence);
|
|
||||||
arme2main.data.niveau = comp.data.niveau;
|
|
||||||
arme2main.data.initiative = RdDUtility.calculInitiative(arme2main.data.niveau, carac[comp.data.defaut_carac].value);
|
|
||||||
armesEquipe.push(arme2main);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return armesEquipe.sort((a, b) => {
|
|
||||||
const nameA = a.name + (a.data.mainInfo ?? '');
|
|
||||||
const nameB = b.name + (b.data.mainInfo ?? '');
|
|
||||||
if (nameA > nameB) return 1;
|
|
||||||
if (nameA < nameB) return -1;
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
static calculInitiative(niveau, caracValue, bonusEcaille = 0) {
|
|
||||||
let base = niveau + Math.floor(caracValue / 2);
|
|
||||||
base += bonusEcaille;
|
|
||||||
return "1d6" + (base >= 0 ? "+" : "") + base;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static computeCarac(data) {
|
static computeCarac(data) {
|
||||||
data.carac.force.value = Math.min(data.carac.force.value, parseInt(data.carac.taille.value) + 4);
|
data.carac.force.value = Math.min(data.carac.force.value, parseInt(data.carac.taille.value) + 4);
|
||||||
@ -709,173 +667,8 @@ export class RdDUtility {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
static processPremierRoundInit() {
|
|
||||||
// Check if we have the whole init !
|
|
||||||
if (game.user.isGM) {
|
|
||||||
let initDone = true;
|
|
||||||
for (let combatant of game.combat.data.combatants) {
|
|
||||||
if (!combatant.initiative) initDone = false;
|
|
||||||
}
|
|
||||||
if (initDone && game.combat.current.round == 1) { // Premier round !
|
|
||||||
for (let combatant of game.combat.data.combatants) {
|
|
||||||
let arme = combatant.initiativeData.arme;
|
|
||||||
//console.log("Parsed !!!", combatant, initDone, game.combat.current, arme);
|
|
||||||
if (arme && arme.type == "arme") {
|
|
||||||
for (let initData of premierRoundInit) {
|
|
||||||
if (arme.data.initpremierround.toLowerCase().includes(initData.pattern)) {
|
|
||||||
let msg = `<h4>L'initiative de ${combatant.actor.name} a été modifiée !</h4>
|
|
||||||
<hr>
|
|
||||||
<div>
|
|
||||||
Etant donné son ${arme.name}, son initative pour ce premier round est désormais de ${initData.init}.
|
|
||||||
</div>`
|
|
||||||
ChatMessage.create({ content: msg });
|
|
||||||
game.combat.setInitiative(combatant._id, initData.init);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
static rollInitiativeCompetence(combatantId, arme) {
|
|
||||||
const combatant = game.combat.getCombatant(combatantId);
|
|
||||||
const actor = combatant.actor;
|
|
||||||
|
|
||||||
let initInfo = "";
|
|
||||||
let initOffset = 0;
|
|
||||||
let caracForInit = 0;
|
|
||||||
let compNiveau = 0;
|
|
||||||
let competence = { name: "Aucune"};
|
|
||||||
if (actor.getSurprise() == "totale") {
|
|
||||||
initOffset = -1; // To force 0
|
|
||||||
initInfo = "Surprise Totale"
|
|
||||||
} else if (actor.getSurprise() == "demi") {
|
|
||||||
initOffset = 0;
|
|
||||||
initInfo = "Demi Surprise"
|
|
||||||
} else if (arme.name == "Autre action") {
|
|
||||||
initOffset = 2;
|
|
||||||
initInfo = "Autre Action"
|
|
||||||
} else if (arme.name == "Draconic") {
|
|
||||||
initOffset = 7;
|
|
||||||
initInfo = "Draconic"
|
|
||||||
} else {
|
|
||||||
initOffset = 3; // Melée = 3.XX
|
|
||||||
competence = RdDItemCompetence.findCompetence(combatant.actor.data.items, arme.data.competence);
|
|
||||||
compNiveau = competence.data.niveau;
|
|
||||||
initInfo = arme.name + " / " + arme.data.competence;
|
|
||||||
|
|
||||||
if (actor.data.type == 'creature' || actor.data.type == 'entite') {
|
|
||||||
caracForInit = competence.data.carac_value;
|
|
||||||
if (competence.data.categorie == "lancer") {
|
|
||||||
initOffset = 5;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
caracForInit = actor.data.data.carac[competence.data.defaut_carac].value;
|
|
||||||
if (competence.data.categorie == "lancer") { // Offset de principe pour les armes de jet
|
|
||||||
initOffset = 4;
|
|
||||||
}
|
|
||||||
if (competence.data.categorie == "tir") { // Offset de principe pour les armes de jet
|
|
||||||
initOffset = 5;
|
|
||||||
}
|
|
||||||
if (competence.data.categorie == "melee") { // Offset de principe pour les armes de jet
|
|
||||||
initOffset = 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let malus = actor.getEtatGeneral(); // Prise en compte état général
|
|
||||||
// Cas des créatures et entités vs personnages
|
|
||||||
let rollFormula = initOffset + "+ ( (" + RdDUtility.calculInitiative(compNiveau, caracForInit) + " + " + malus + ") /100)";
|
|
||||||
// Garder la trace de l'arme/compétence utilisée pour l'iniative
|
|
||||||
combatant.initiativeData = { arme: arme } // pour reclasser l'init au round 0
|
|
||||||
game.combat.rollInitiative(combatantId, rollFormula, { initInfo: initInfo});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
static buildListeActionsCombat(combatant) {
|
|
||||||
const actor = combatant.actor; // Easy access
|
|
||||||
let items = actor.data.items;
|
|
||||||
let actions = []
|
|
||||||
if (actor.isCreature()) {
|
|
||||||
actions = actions.concat(items.filter(it => RdDItemCompetenceCreature.isCompetenceAttaque(it))
|
|
||||||
.map(competence => RdDItemCompetenceCreature.toArme(competence)));
|
|
||||||
} else {
|
|
||||||
// Recupération des items 'arme'
|
|
||||||
let armes = items.filter(it => RdDItemArme.isArmeUtilisable(it))
|
|
||||||
.map(arme => duplicate(arme)) /* pas de changements aux armes d'origine */
|
|
||||||
.concat(RdDItemArme.mainsNues());
|
|
||||||
|
|
||||||
let competences = items.filter(it => it.type == 'competence');
|
|
||||||
actions = actions.concat(this._finalizeArmeList(armes, competences, actor.data.data.carac));
|
|
||||||
|
|
||||||
actions.push({ name: "Draconic", data: { initOnly: true, competence: "Draconic" } });
|
|
||||||
}
|
|
||||||
|
|
||||||
actions.push({ name: "Autre action", data: { initOnly: true, competence: "Autre action" } });
|
|
||||||
for (let index = 0; index < actions.length; index++) {
|
|
||||||
actions[index].index = index;
|
|
||||||
}
|
|
||||||
return actions;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
static displayInitiativeMenu(html, combatantId) {
|
|
||||||
const combatant = game.combat.getCombatant(combatantId);
|
|
||||||
let armesList = this.buildListeActionsCombat(combatant);
|
|
||||||
|
|
||||||
// Build the relevant submenu
|
|
||||||
if (armesList) {
|
|
||||||
let menuItems = [];
|
|
||||||
for (let arme of armesList) {
|
|
||||||
menuItems.push({
|
|
||||||
name: arme.data.competence,
|
|
||||||
icon: "<i class='fas fa-dice-d6'></i>",
|
|
||||||
callback: target => { RdDUtility.rollInitiativeCompetence(combatantId, arme) }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
new ContextMenu(html, ".directory-list", menuItems).render();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
static incDecInit(combatantId, incDecValue) {
|
|
||||||
const combatant = game.combat.getCombatant(combatantId);
|
|
||||||
let initValue = combatant.initiative + incDecValue;
|
|
||||||
game.combat.setInitiative(combatantId, initValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
static pushInitiativeOptions(html, options) {
|
|
||||||
for (let i = 0; i < options.length; i++) {
|
|
||||||
let option = options[i];
|
|
||||||
if (option.name == 'COMBAT.CombatantReroll') { // Replace !
|
|
||||||
option.name = "Sélectionner l'initiative...";
|
|
||||||
option.condition = true;
|
|
||||||
option.icon = '<i class="far fa-question-circle"></i>';
|
|
||||||
option.callback = target => {
|
|
||||||
RdDUtility.displayInitiativeMenu(html, target.data('combatant-id'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
options.push({
|
|
||||||
name: "Incrémenter initiative",
|
|
||||||
condition: true,
|
|
||||||
icon: '<i class="fas fa-plus"></i>',
|
|
||||||
callback: target => {
|
|
||||||
RdDUtility.incDecInit(target.data('combatant-id'), +0.01);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
options.push({
|
|
||||||
name: "Décrémenter initiative",
|
|
||||||
condition: true,
|
|
||||||
icon: '<i class="fas fa-minus"></i>',
|
|
||||||
callback: target => {
|
|
||||||
RdDUtility.incDecInit(target.data('combatant-id'), -0.01);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static async chatListeners(html) {
|
static async chatListeners(html) {
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
{{#if rolled.isSuccess}}
|
{{#if rolled.isSuccess}}
|
||||||
{{alias}} réussit sa recette, avec un plat de {{qualiteFinale}} pour {{oeuvre.data.sust}} Points de Sustentation.
|
{{alias}} réussit sa recette, avec un plat de {{qualiteFinale}} pour {{oeuvre.data.sust}} Points de Sustentation.
|
||||||
{{else}}
|
{{else}}
|
||||||
{{alias}} fait un pière cuisinier(e), et obtient {{#if (lt qualiteFinale 0)}}un plat à l'exotisme certain{{else}}un plat de qualité {{qualiteFinale}}{{/if}}.
|
{{alias}} fait un piètre cuisinier(e), et obtient {{#if (lt qualiteFinale 0)}}un plat à l'exotisme certain{{else}}un plat de qualité {{qualiteFinale}}{{/if}}.
|
||||||
Selon la décision du MJ, le plat peut fournir {{oeuvre.data.sust}} Points de Sustentation
|
Selon la décision du MJ, le plat peut fournir {{oeuvre.data.sust}} Points de Sustentation
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user