243 lines
8.4 KiB
JavaScript
243 lines
8.4 KiB
JavaScript
/* -------------------------------------------- */
|
|
import { VadentisCombat } from "./vadentis-combat.js";
|
|
|
|
/* -------------------------------------------- */
|
|
export class VadentisUtility {
|
|
|
|
/* -------------------------------------------- */
|
|
static async preloadHandlebarsTemplates() {
|
|
|
|
const templatePaths = [
|
|
'systems/foundryvtt-vadentis/templates/actor-sheet.html',
|
|
'systems/foundryvtt-vadentis/templates/item-sheet.html',
|
|
'systems/foundryvtt-vadentis/templates/editor-notes-gm.html',
|
|
'systems/foundryvtt-vadentis/templates/hud-actor-attaque.html',
|
|
'systems/foundryvtt-vadentis/templates/hud-actor-sort.html'
|
|
]
|
|
return loadTemplates(templatePaths);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static updateCombat( combat, round, diff, id ) {
|
|
if (game.user.isGM && combat.round != 0 && combat.turns && combat.active) {
|
|
let turn = combat.turns.find(t => t.tokenId == combat.current.tokenId);
|
|
ChatMessage.create( { content: `Round ${combat.round} : C'est au tour de ${turn.actor.name}<br>` } );
|
|
|
|
canvas.tokens.get(turn.token._id).control();
|
|
canvas.tokens.cycleTokens(1, true);
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static createOptionList( min, max) {
|
|
let options = ""
|
|
for(let i=min; i<=max; i++) {
|
|
options += `<option value="${i}">${i}</option>\n`;
|
|
}
|
|
return options;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static createDirectOptionList( min, max) {
|
|
let options = {};
|
|
for(let i=min; i<=max; i++) {
|
|
options[`${i}`] = `${i}`;
|
|
}
|
|
return options;
|
|
}
|
|
/* -------------------------------------------- */
|
|
static createDirectIntegerOptionList( min, max) {
|
|
let options = {};
|
|
for(let i=min; i<=max; i++) {
|
|
options[i] = `${i}`;
|
|
}
|
|
return options;
|
|
}
|
|
/* -------------------------------------------- */
|
|
static createDirectReverseOptionList( min, max) {
|
|
let options = {};
|
|
for(let i=max; i>=min; i--) {
|
|
options[`${i}`] = `${i}`;
|
|
}
|
|
return options;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static getTarget() {
|
|
if (game.user.targets && game.user.targets.size == 1) {
|
|
for (let target of game.user.targets) {
|
|
return target;
|
|
}
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static processDamageString( formula, actor ) {
|
|
let workFormula = formula.toLowerCase();
|
|
if ( workFormula.includes('bonus de force')) {
|
|
workFormula = workFormula.replace('bonus de force', actor.getForceScore());
|
|
}
|
|
return workFormula;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static async processRoll( formula, rollMode ) {
|
|
let myRoll = new Roll(formula);
|
|
myRoll.roll( { async: false} );
|
|
if (game.modules.get("dice-so-nice")?.active) {
|
|
await game.dice3d.showForRoll(myRoll, game.user, true);
|
|
}
|
|
return myRoll;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static async performAttack( combatData) {
|
|
let attacker = game.actors.get(combatData.attackerActorId);
|
|
let defender = game.actors.get(combatData.targetActorId);
|
|
console.log("ATTACK !!", attacker, defender);
|
|
if( attacker && defender) {
|
|
let defense = defender.getDefenseScore();
|
|
let attaque = attacker.getAttaqueScore();
|
|
|
|
let msgData = {
|
|
alias: this.name,
|
|
title: `${attacker.name} attaque ${defender.name}`
|
|
}
|
|
|
|
let tirMsg = "";
|
|
if ( combatData.arme.type == 'tir') {
|
|
attacker.decrementeMunition(combatData.arme);
|
|
tirMsg += `<br>C'est un tir, les munitions de l'attaquant ont été décrémentées`;
|
|
}
|
|
|
|
let formulaTouche = "1d20+"+attaque;
|
|
let formulaFull = attacker.buildTexteFormula( attacker.system.combat.attaque );
|
|
let myRoll = await this.processRoll(formulaTouche);
|
|
if (myRoll.dice[0].results[0].result > 1 && myRoll.total >= defense) { // Success !
|
|
let degats = `normaux : ${combatData.arme.system.damage}`;
|
|
let formula = combatData.arme.system.damage.toLowerCase();
|
|
msgData.msg = `${attacker.name} a réussi son attaque sur ${defender.name} (${formulaFull} => ${myRoll.total} / ${defense}) !<br> Les dégâts sont ${degats}.`;
|
|
|
|
msgData.msg += tirMsg;
|
|
if ( myRoll.dice[0].results[0].result >= combatData.arme.system.valuecritical ) {
|
|
degats = `critiques : ${combatData.arme.system.criticaldamage}`;
|
|
formula = combatData.arme.system.criticaldamage.toLowerCase();
|
|
msgData.msg += `<br>C'est une <strong>réussite critique</strong> !`;
|
|
}
|
|
msgData.img = 'systems/foundryvtt-vadentis/images/icons/tchat_attaque_réussie.webp'
|
|
|
|
formula = this.processDamageString( formula, attacker );
|
|
let degatsRoll = await this.processRoll(formula);
|
|
msgData.msg +=`<br>Les dégats infligés sont de <strong>${degatsRoll.total}</strong> (${formula}).`;
|
|
defender.applyDamage( degatsRoll.total );
|
|
} else { //Echec
|
|
msgData.img = 'systems/foundryvtt-vadentis/images/icons/tchat_attaque_échouée.webp';
|
|
if ( myRoll.dice[0].results[0].result == 1) {
|
|
msgData.msg = `${attacker.name} a fait un <strong>échec critique</strong> et a raté son attaque sur ${defender.name} (${myRoll.total} / ${defense}) !`;
|
|
} else {
|
|
msgData.msg = `${attacker.name} a raté son attaque sur ${defender.name} (${myRoll.total} / ${defense}) !`;
|
|
}
|
|
msgData.msg += tirMsg;
|
|
}
|
|
ChatMessage.create({
|
|
//whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
|
|
content: await renderTemplate(`systems/foundryvtt-vadentis/templates/chat-generic-result.html`, msgData)
|
|
});
|
|
} else {
|
|
ui.notifications.warn("Impossible de trouver l'attaquant et le défenseur.")
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static buildJetText( stat) {
|
|
let name = stat.label;
|
|
let title = `Jet de ${name}`;
|
|
if ( name.toLowerCase().substr(0,1).match(/[aeoiou]/g) ) {
|
|
title = `Jet d'${name}`;
|
|
}
|
|
return title;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static registerChatCallbacks( ) {
|
|
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static fillRange (start, end) {
|
|
return Array(end - start + 1).fill().map((item, index) => start + index);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static onSocketMesssage( msg ) {
|
|
if( !game.user.isGM ) return; // Only GM
|
|
|
|
if (msg.name == 'msg_attack' ) {
|
|
this.performAttack( msg.data );
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static async loadCompendiumNames(compendium) {
|
|
const pack = game.packs.get(compendium);
|
|
let competences;
|
|
await pack.getIndex().then(index => competences = index);
|
|
return competences;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static async loadCompendium(compendium, filter = item => true) {
|
|
let compendiumItems = await SoSUtility.loadCompendiumNames(compendium);
|
|
|
|
const pack = game.packs.get(compendium);
|
|
let list = [];
|
|
for (let compendiumItem of compendiumItems) {
|
|
await pack.getEntity(compendiumItem._id).then(it => {
|
|
const item = it.data;
|
|
if (filter(item)) {
|
|
list.push(item);
|
|
}
|
|
});
|
|
};
|
|
return list;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static getDonnees( ) {
|
|
return this.loadCompendiumNames('foundryvtt-vadentis.donnees');
|
|
}
|
|
/* -------------------------------------------- */
|
|
static getEglises( ) {
|
|
return this.loadCompendiumNames('foundryvtt-vadentis.croyances');
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static async confirmDelete(actorSheet, li) {
|
|
let itemId = li.data("item-id");
|
|
let msgTxt = "<p>Etes vous certain de souhaiter supprimer cet item ?";
|
|
let buttons = {
|
|
delete: {
|
|
icon: '<i class="fas fa-check"></i>',
|
|
label: "Oui, à supprimer",
|
|
callback: () => {
|
|
actorSheet.actor.deleteEmbeddedDocuments('Item', [ itemId] );
|
|
li.slideUp(200, () => actorSheet.render(false));
|
|
}
|
|
},
|
|
cancel: {
|
|
icon: '<i class="fas fa-times"></i>',
|
|
label: "Annuler"
|
|
}
|
|
}
|
|
msgTxt += "</p>";
|
|
let d = new Dialog({
|
|
title: "Confirmer la suppression",
|
|
content: msgTxt,
|
|
buttons: buttons,
|
|
default: "cancel"
|
|
});
|
|
d.render(true);
|
|
}
|
|
|
|
} |