/* -------------------------------------------- */ import { VadentisUtility } from "./vadentis-utility.js"; /* -------------------------------------------- */ const MIN_PV = -50; const MIN_PE = -50; /* -------------------------------------------- */ /** * Extend the base Actor entity by defining a custom roll data structure which is ideal for the Simple system. * @extends {Actor} */ export class VadentisActor extends Actor { /* -------------------------------------------- */ /** * Override the create() function to provide additional SoS functionality. * * This overrided create() function adds initial items * Namely: Basic skills, money, * * @param {Object} data Barebones actor data which this function adds onto. * @param {Object} options (Unused) Additional options which customize the creation workflow. * */ static async create(data, options) { // Case of compendium global import if (data instanceof Array) { return super.create(data, options); } // If the created actor has items (only applicable to duplicated actors) bypass the new actor creation logic if (data.items) { let actor = super.create(data, options); return actor; } return super.create(data, options); } /* -------------------------------------------- */ async prepareData() { super.prepareData(); } /* -------------------------------------------- */ getCompetences() { return duplicate( this.items.filter( item => item.type == 'competence') || [] ); } /* -------------------------------------------- */ getDonnees() { return duplicate( this.items.filter( item => item.type == 'donnee')|| [] ); } /* -------------------------------------------- */ getEglises() { return duplicate( this.items.filter( item => item.type == 'eglise')|| [] ); } /* -------------------------------------------- */ getSorts() { return duplicate( this.items.filter( item => item.type == 'sort')|| [] ); } /* -------------------------------------------- */ getAttributs() { return duplicate( this.items.filter( item => item.type == 'attribut')|| [] ); } /* -------------------------------------------- */ getTechniques() { return duplicate( this.items.filter( item => item.type == 'technique') || [] ); } /* -------------------------------------------- */ getDevotions() { return duplicate(this.items.filter( item => item.type == 'devotion')|| [] ); } /* -------------------------------------------- */ getEquipements() { return duplicate(this.items.filter( item => item.type == 'equipement' ) || [] ); } /* -------------------------------------------- */ getArmes() { return duplicate(this.items.filter( item => item.type == 'armecc' || item.type == 'tir' ) || [] ); } /* -------------------------------------------- */ getArmures() { return duplicate(this.items.filter( item => item.type == 'armurebouclier' ) || [] ); } /* -------------------------------------------- */ getMonnaies() { return duplicate(this.items.filter( item => item.type == 'monnaie' ) || [] ); } /* -------------------------------------------- */ async updateCompetence( name, field, value) { let competence = this.items.find( item => item.type == 'competence' && item.name == name); if (competence) { let dataPath = 'system.'+field; await this.updateEmbeddedDocuments( "Item", [{ _id: competence.id, [dataPath]:value }] ); } } /* -------------------------------------------- */ async equiperObject( equipementId ) { let item = this.items.get(equipementId) if (item) { let update = { _id: item.id, "system.equipee": !item.system.equipee }; await this.updateEmbeddedDocuments("Item", [ update ] ); } } /* -------------------------------------------- */ buildListeActionsCombat( ) { let armes = []; } /* -------------------------------------------- */ calculerSommeStats( ) { for (const key in this.system.combat) { let combatData = this.system.combat[key]; combatData.total = combatData.base + combatData.malus + combatData.bonus; } for (const key in this.system.magie) { let magieData = this.system.magie[key]; magieData.total = magieData.base + magieData.malus + magieData.bonus; } } /* -------------------------------------------- */ async processSortDevotion( name, devotionSort ) { if ( this.system.stats.pointsenergie.value == 0) { // Vérification du ~ de points d'énergie ChatMessage.create({ content: `${this.name} n'a pas assez de Points d'Energie pour lancer ${name} ${devotionSort.name}` } ); return; } let scores = this.system.magie[(name =="devotion") ? 'devotion': 'matriseelementaire']; let statValue = scores.base + scores.malus + scores.bonus; let formulaFull = this.buildTexteFormula( scores ); let myRoll = await VadentisUtility.processRoll("1d20+"+statValue ); let msgData = { alias: this.name, title: `Sort ${devotionSort.name}`, isSort: true } if (myRoll.dice[0].results[0].result > 1 && myRoll.total >= devotionSort.system.difficulty) { msgData.img = 'systems/foundryvtt-vadentis/images/icons/tchat_sort_réussi.webp'; msgData.msg = `${this.name} a réussi son ${name} et perd ${devotionSort.system.pe} Points d'Energie (lancer : ${formulaFull} => ${myRoll.total} / ${devotionSort.system.difficulty}).`; let maintain = (devotionSort.system.ismaintain)?"Oui":"Non"; let complex = (devotionSort.system.complexactions)?"Oui":"Non"; msgData.msg += `
Peut être maintenu: ${maintain}
Actions complexes : ${complex}`; if ( !devotionSort.system.notes) devotionSort.system.notes = ""; msgData.msg += `
Description : ${devotionSort.system.notes.replace(/<\/?[^>]+(>|$)/g, "")}`; let newEnergie = this.system.stats.pointsenergie.value - devotionSort.system.pe; await this.update( {'system.stats.pointsenergie.value': newEnergie }); if (myRoll.dice[0].results[0].result >= devotionSort.system.valuecritical ) { // Critique ? msgData.img = 'systems/foundryvtt-vadentis/images/icons/tchat_réussite_critique.webp'; msgData.msg += "
C'est une réussite critique !"; msgData.msg += `
Effet critique : ${devotionSort.system.criticaleffect.replace(/<\/?[^>]+(>|$)/g, "")}`; } else { msgData.msg += `
Effet : ${devotionSort.system.effect.replace(/<\/?[^>]+(>|$)/g, "")}`; } if ( devotionSort.system.damage != "") { let formula = devotionSort.system.damage; if (myRoll.dice[0].results[0].result >= devotionSort.system.valuecritical ) { // Critique ? msgData.msg += `
Et provoque les dégats critiques suivants : [[/roll ${devotionSort.system.damagecritical}]]`; formula = devotionSort.system.damagecritical; } else { msgData.msg += `
Et provoque les dégats suivants : [[/roll ${devotionSort.system.damage}]]`; } } if ( newEnergie < 0) { msgData.msg += `
Attention : Les Points d'Energie de ${this.name} sont négatifs ! Il convient d'éditer ses Points de Vie en conséquence.`; } } else { msgData.img = 'systems/foundryvtt-vadentis/images/icons/tchat_sort_échoué.webp'; if (myRoll.dice[0].results[0].result == 1 ) { // Critique ? msgData.img = 'systems/foundryvtt-vadentis/images/icons/tchat_échec_critique.webp'; msgData.msg = `${this.name} a fait un échec critique à son lancer de ${name}`; } else { msgData.msg = `${this.name} a échoué son lancer de ${name}`; } } console.log(devotionSort.system.description, msgData); ChatMessage.create({ //whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name), content: await renderTemplate(`systems/foundryvtt-vadentis/templates/chat-generic-result.html`, msgData) }); } /* -------------------------------------------- */ async rollDamage( weapon, damageType ) { let formula = VadentisUtility.processDamageString( weapon.system[damageType], this ); let degatsRoll = await VadentisUtility.processRoll( formula ); let msgData = { alias: this.name, img: "systems/foundryvtt-vadentis/images/icons/tchat_dégâts_infligés.webp", title: `Dégâts de ${weapon.name}`, msg: `${this.name} frappe avec ${weapon.name} et produit ${degatsRoll.total} Points de Dégâts (${formula}).` } ChatMessage.create({ //whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name), content: await renderTemplate(`systems/foundryvtt-vadentis/templates/chat-generic-result.html`, msgData) }); } /* -------------------------------------------- */ async rollSortDevotionDamage( sort, damageType ) { let formula = VadentisUtility.processDamageString( sort.system[damageType], this ); let degatsRoll = await VadentisUtility.processRoll( formula ); let msgData = { alias: this.name, img: "systems/foundryvtt-vadentis/images/icons/tchat_dégâts_infligés.webp", title: `Dégâts de ${sort.name}`, msg: `Le sort ${sort.name} produit ${degatsRoll.total} Points de Dégâts (${formula}).` } ChatMessage.create({ //whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name), content: await renderTemplate(`systems/foundryvtt-vadentis/templates/chat-generic-result.html`, msgData) }); } /* -------------------------------------------- */ async applyDamage( damageValue ) { let pvData = this.system.stats.pointsvie; let newValue = Math.max( pvData.value - damageValue, MIN_PV); await this.update( {'system.stats.pointsvie.value': newValue }); let msgData = { alias: this.name, img: "systems/foundryvtt-vadentis/images/icons/tchat_dégâts_infligés.webp", title: `${this.name} encaisse des dégâts !`, msg: `${this.name} encaisse ${damageValue} dégâts !` } ChatMessage.create({ //whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name), content: await renderTemplate(`systems/foundryvtt-vadentis/templates/chat-generic-result.html`, msgData) }); if ( game.user.isGM) { msgData.msg = `
Ses Points de Vie actuels sont désormais de ${newValue}.`; ChatMessage.create({ whisper: ChatMessage.getWhisperRecipients( 'GM'), content: await renderTemplate(`systems/foundryvtt-vadentis/templates/chat-generic-result.html`, msgData) }); } } /* -------------------------------------------- */ _getCombatValue(mydata) { if ( typeof mydata.base == 'number' ) { return mydata.base + mydata.malus + mydata.bonus; } else { return Number(mydata.base[0]) + Number(mydata.malus[0]) + Number(mydata.bonus[0]); } } /* -------------------------------------------- */ getInitiativeScore( ) { let initData = this.system.combat.initiative; return this._getCombatValue( initData); } /* -------------------------------------------- */ getDefenseScore( ) { let defenseData = this.system.combat.defense; return this._getCombatValue( defenseData); } /* -------------------------------------------- */ getForceScore( ) { let forceData = this.system.combat.force; return this._getCombatValue( forceData); } /* -------------------------------------------- */ getAttaqueScore( ) { let attaqueData = this.system.combat.attaque; return this._getCombatValue( attaqueData); } /* -------------------------------------------- */ buildTexteFormula( stat) { let signMalus = (stat.malus < 0) ? "" : "+"; return `1d20+ ${stat.base} ${signMalus} ${stat.malus} + ${stat.bonus}`; } /* -------------------------------------------- */ async rollSort( sortId ) { let sort = this.items.get( sortId ); if ( sort ) { sort = duplicate(sort) this.processSortDevotion( "sort", sort); } } /* -------------------------------------------- */ async rollDevotion( devotionId ) { let devotion = this.items.get( devotionId ); if ( devotion ) { devotion = duplicate(devotion) this.processSortDevotion( "devotion", devotion); } } /* -------------------------------------------- */ rollSortOuDevotion( sortId ) { let sort = this.items.get( sortId ); this.processSortDevotion( sort.type, sort); } /* -------------------------------------------- */ async rollTechnique( techniqueId ) { let technique = this.items.get( techniqueId ) if (technique) { technique = duplicate(technique) let msgData = { alias: this.name, img: technique.img, title: `Technique ${technique.name}` } if ( this.system.stats.pointsadrenaline.value < technique.system.pacost) { // Vérification du ~ de points d'adrénaline msgData.msg = `${this.name} n'a pas assez de Points d'Adrénaline pour éxecuter sa technique ${technique.name}`; } else { let newAdrenaline = this.system.stats.pointsadrenaline.value - technique.system.pacost; await this.update( {'system.stats.pointsadrenaline.value': newAdrenaline }); msgData.msg = `${this.name} execute sa technique ${technique.name}, pour un côut de ${technique.system.pacost} Points d'Adrénaline
Les effets sont : ${technique.system.effect}`; } ChatMessage.create({ //whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name), content: await renderTemplate(`systems/foundryvtt-vadentis/templates/chat-generic-result.html`, msgData) }); } else { ui.notifications.warn("Technique non trouvée"); } } /* -------------------------------------------- */ async rollCompetence( competenceId ) { console.log(competenceId) let competence = this.items.get( competenceId); if ( competence) { competence = duplicate(competence) let msgData = { alias: this.name, img: competence.img, rollMode: game.settings.get("core", "rollMode"), title: `Compétence ${competence.name}` } let statValue = competence.system.base + competence.system.malus + competence.system.bonus; let formulaFull = this.buildTexteFormula( competence.system ); let myRoll = await VadentisUtility.processRoll("1d20+"+statValue, msgData.rollMode ); msgData.msg = `${formulaFull} => ${myRoll.total}`; console.log(formulaFull, myRoll) if (myRoll.dice[0].results[0].result == 1 ) { // Critique ? msgData.img = 'systems/foundryvtt-vadentis/images/icons/tchat_échec_critique.webp'; msgData.msg += `
C'est un échec critique !`; } if (myRoll.dice[0].results[0].result == 20 ) { // Critique ? msgData.img = 'systems/foundryvtt-vadentis/images/icons/tchat_réussite_critique.webp'; msgData.msg += `
C'est une réussite critique !`; } if (["gmroll", "blindroll"].includes(msgData.rollMode)) msgData["whisper"] = ChatMessage.getWhisperRecipients("GM").map(u => u.id); if (msgData.rollMode === "blindroll") msgData["blind"] = true; else if (msgData.rollMode === "selfroll") msgData["whisper"] = [game.user]; ChatMessage.create({ whisper: msgData["whisper"], content: await renderTemplate(`systems/foundryvtt-vadentis/templates/chat-generic-result.html`, msgData) }); } else { ui.notifications.warn("Compétence non trouvée"); } } /* -------------------------------------------- */ async genericRoll( stat, key ) { let statValue = this._getCombatValue( stat ); let formulaFull = this.buildTexteFormula( stat ); let myRoll = await VadentisUtility.processRoll("1d20+"+statValue ); let msgData = { alias: this.name, img: `systems/foundryvtt-vadentis/images/icons/feuille_perso_${key}.webp`, title: VadentisUtility.buildJetText( stat), msg: `${formulaFull} => ${myRoll.total}` } if (myRoll.dice[0].results[0].result == 1 ) { // Critique ? msgData.img = 'systems/foundryvtt-vadentis/images/icons/tchat_échec_critique.webp'; msgData.msg += `
C'est un échec critique !`; } if (myRoll.dice[0].results[0].result == 20 ) { // Critique ? msgData.img = 'systems/foundryvtt-vadentis/images/icons/tchat_réussite_critique.webp'; msgData.msg += `
C'est une réussite critique !`; } ChatMessage.create({ //whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name), content: await renderTemplate(`systems/foundryvtt-vadentis/templates/chat-generic-result.html`, msgData) }); } /* -------------------------------------------- */ async rollCombat( combatName ) { let stat = this.system.combat[combatName]; this.genericRoll( stat, combatName ); } /* -------------------------------------------- */ rollMagie( magieName ) { let stat = this.system.magie[magieName]; this.genericRoll( stat, magieName ); } /* -------------------------------------------- */ async incrementeArgent( arme ) { let monnaie = this.items.find( item => item.type == 'monnaie' && item.name == arme.name); if (monnaie) { monnaie = duplicate(monnaie) let newValeur = monnaie.system.nombre + 1; await this.updateEmbeddedDocuments( 'Item', [{ _id: monnaie._id, 'system.nombre': newValeur }] ); } } /* -------------------------------------------- */ async decrementeArgent( arme ) { let monnaie = this.items.find( item => item.type == 'monnaie' && item.name == arme.name); if (monnaie) { monnaie = duplicate(monnaie) let newValeur = monnaie.system.nombre - 1; newValeur = (newValeur <= 0) ? 0 : newValeur; await this.updateEmbeddedDocuments( "Item", [{ _id: monnaie._id, 'system.nombre': newValeur }] ); } } /* -------------------------------------------- */ async incrementeMunition( arme ) { let armeTir = this.items.find( item => item.type == 'tir' && item.name == arme.name); if (armeTir) { armeTir = duplicate(armeTir) let newMunition = armeTir.system.munition + 1; await this.updateEmbeddedDocuments( "Item", [{ _id: armeTir._id, 'system.munition': newMunition }] ); } } /* -------------------------------------------- */ async decrementeMunition( arme ) { let armeTir = this.items.find( item => item.type == 'tir' && item.name == arme.name); if (armeTir) { armeTir = duplicate(armeTir) let newMunition = armeTir.system.munition - 1; newMunition = (newMunition <= 0) ? 0 : newMunition; await this.updateEmbeddedDocuments( "Item", [{ _id: armeTir._id, 'system.munition': newMunition } ]); } } /* -------------------------------------------- */ async incrementeQuantite( objet ) { let objetQ = this.items.find( item => item._id == objet._id ); if (objetQ) { objetQ = duplicate(objetQ) let newQ = objetQ.system.quantite + 1; await this.updateEmbeddedDocuments( "Item", [{ _id: objetQ._id, 'system.quantite': newQ } ] ); } } /* -------------------------------------------- */ async decrementeQuantite( objet ) { let objetQ = this.items.find( item => item._id == objet._id ); if (objetQ) { objetQ = duplicate(objetQ) let newQ = objetQ.system.quantite - 1; newQ = (newQ <= 0) ? 0 : newQ; await this.updateEmbeddedDocuments( "Item", [{ _id: objetQ._id, 'system.quantite': newQ } ]); } } /* -------------------------------------------- */ rollArme(armeId) { let target = VadentisUtility.getTarget(); if ( target ) { let arme = this.items.find( item => (item.type == 'armecc' || item.type == 'tir') && item.id == armeId); if (arme) { arme = duplicate(arme) if ( arme.type == 'tir' && arme.system.munition <= 0 ) { ui.notifications.warn("Vous n'avez plus de munitions avec cette arme."); return; } let combatData = { attackerActorId: this.id, targetActorId: target.actor.id, arme: duplicate(arme) } if (game.user.isGM) { VadentisUtility.performAttack( combatData); } else { game.socket.emit("system.foundryvtt-vadentis", { name: "msg_attack", data: combatData } ); } } } else { ui.notifications.warn("Vous devez désigner une cible pour attaquer avec une arme.") } } }