/** * Extend the base Actor entity by defining a custom roll data structure which is ideal for the Simple system. * @extends {Actor} */ import { RdDUtility } from "./rdd-utility.js"; export class RdDActor extends Actor { /* -------------------------------------------- */ /** * Override the create() function to provide additional RdD 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) { // If the created actor has items (only applicable to duplicated actors) bypass the new actor creation logic if (data.items) { return super.create(data, options); } super.create(data, options); } /* -------------------------------------------- */ prepareData() { super.prepareData(); const actorData = this.data; const data = actorData.data; const flags = actorData.flags; // Make separate methods for each Actor type (character, npc, etc.) to keep // things organized. if (actorData.type === 'personnage') this._prepareCharacterData(actorData); } /** * Prepare Character type specific data */ _prepareCharacterData(actorData) { // Initialize empty items RdDUtility.computeCarac(actorData.data); } /* -------------------------------------------- */ performRoll( rollData ) { let myroll = new Roll("d100"); myroll.roll(); let quality = "Echec"; let xpmsg = ""; let tache = 0; //console.log(">>> ROLL", rollData.selectedCarac.label, rollData.rollTarget.score, myroll.total ); let result = myroll.total; if (result <= rollData.rollTarget.part) { quality = "Réussite Particulière!"; if ( rollData.finalLevel < 0 ) { let xpcarac = Math.floor( Math.abs(rollData.finalLevel) / 2); let xpcomp = (Math.abs(rollData.finalLevel) % 2 == 1) ? xpcarac+1 : xpcarac; xpmsg = "
Points d'expérience gagné ! " + xpcarac + " - " + xpcomp; } tache = 4; } else if (result <= (rollData.rollTarget.score /2) ) { quality = "Réussite Significative"; tache = 2; } else if (result <= (rollData.rollTarget.score) ) { quality = "Réussite Normale"; tache = 1; } else if (result < (rollData.rollTarget.epart) ) { quality = "Echec Normal"; tache = 0; } else if (result < (rollData.rollTarget.etotal) ) { quality = "Echec Particulier"; tache = -2; } else if (result >= (rollData.rollTarget.etotal) ) { quality = "Echec Total"; tache = -4; } let chatOptions = { "content": "Test : " + rollData.selectedCarac.label + " / " + rollData.competence.name + "
Jet : " + rollData.selectedCarac.value + " / " + rollData.finalLevelStr + " - " + rollData.rollTarget.score + "%
Résutat : " + myroll.total + "
" + "" + quality + "
Points de taches : " + tache + xpmsg, "title": "Test" } ChatMessage.create( chatOptions ); } /* -------------------------------------------- */ updateCarac( caracName, caracValue ) { let data = this.data.data; data.carac[caracName].value = caracValue; // Force update ? RdDUtility.computeCarac( data ); } /* -------------------------------------------- */ async updateCompetence( compName, compValue ) { let comp = RdDUtility.findCompetence( this.data.items, compName); if ( comp ) { //console.log("ACTOR", this); //comp.data.niveau = compValue; const update = {_id: comp._id, 'data.niveau': compValue }; const updated = await this.updateEmbeddedEntity("OwnedItem", update); // Updates one EmbeddedEntity //console.log("UP", updated); } else { console.log("Competence not found", compName); } } /* -------------------------------------------- */ computeEtatGeneral( ) { let data = this.data.data; let state = 0; state = state - (data.sante.vie.max - data.sante.vie.value); state = state + RdDUtility.currentFatigueMalus(data.sante.fatigue.value, data.sante.endurance.max); data.compteurs.etat.value = state; } /* -------------------------------------------- */ testSiSonne( endurance ) { let myroll = new Roll("d20"); myroll.roll(); let result = myroll.total; if ( result <= endurance.value) this.data.data.sante.sonne.value = false; if ( result > endurance.value || result == 20) // 20 is always a failure this.data.data.sante.sonne.value = true; if (result == 1) { this.data.data.sante.sonne.value = false; this.data.data.carac.constitution.xp++; // 1 XP on 1 ! } } /* -------------------------------------------- */ santeIncDec(name, inc ) { let data = this.data.data.sante[name]; let lastValue = data.value; // Useful for Endurance and Sonné data.value = data.value + inc; if ( data.value > data.max ) data.value = data.max; if ( data.value < 0 ) data.value = 0; if (name == "endurance") { if ( inc < 0 ) // Each endurance lost -> fatigue lost this.data.data.sante.fatigue.value = this.data.data.sante.fatigue.value - inc // If endurance is 0 -> -1 vie if ( data.value == 0 ) { this.data.data.sante.vie.value = this.data.data.sante.vie.value - 1; } let diffVie = this.data.data.sante.vie.max - this.data.data.sante.vie.value; if ( data.value > data.max - (diffVie*2) ) { data.value = data.max - (diffVie*2); } let blessures = this.data.data.blessures; let maxEnd = Math.floor( data.max / blessures.graves.nombre); if (data.value > maxEnd ) data.value = maxEnd; if ( blessures.critiques.nombre > 0 && data.value > 1) data.value = 1; if (lastValue - data.value > 1) this.testSiSonne(data); // Peut-être sonné si 2 points d'endurance perdus d'un coup } let diffEndurance = this.data.data.sante.endurance.max - this.data.data.sante.endurance.value; if ( this.data.data.sante.fatigue.value < diffEndurance) // If endurance lost, then the same amount of fatigue cannot be recovered this.data.data.sante.fatigue.value = diffEndurance; console.log(">>>> NEW VI", name, data.value); this.computeEtatGeneral(); } /* -------------------------------------------- */ rollArme( armeName ) { // TODO : Search the weapon in the items // TODO : Get the associated compentence // TODO call rollCompetence with the comp+arme } /* -------------------------------------------- */ async rollCompetence( compName, arme ) { let compItem = RdDUtility.findCompetence( this.data.items, compName); let rollData = { "competence": compItem, "carac": this.data.data.carac, "bonusmalusTable": CONFIG.RDD.bonusmalus, "etat": this.data.data.compteurs.etat.value, "bmValue": 0, "arme": arme, "finalLevel": 0 } let dlg = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-competence.html', rollData); let mydialog = new Dialog( { title: "Test de compétence", content: dlg, buttons: { rollButton: { label: "Lancer", callback: html => this.performRoll(html) } }, default: "rollButton" }, { classes: ["rdddialog"], width: 600, height: 360 } ); mydialog.data.rollData = rollData; mydialog.data.actor = this; mydialog.activateListeners = function(html) { // Get the rollData stuff var rollData = this.data.rollData; function updateRollResult( rollData ) { rollData.finalLevel = parseInt(rollData.competence.data.niveau) + parseInt(rollData.bmValue) + parseInt(rollData.etat); rollData.finalLevelStr = (rollData.finalLevel >= 0 ) ? "+" + rollData.finalLevel : rollData.finalLevel; $("#roll-param").text( rollData.selectedCarac.value + " / " + rollData.finalLevelStr ); rollData.rollTarget = game.data.RdDUtility.getResolutionField( rollData.selectedCarac.value, rollData.finalLevel); let niveauStr = (rollData.competence.data.niveau >= 0) ? "+" + rollData.competence.data.niveau : rollData.competence.data.niveau; $("#compdialogTitle").text( rollData.competence.name + " - " + niveauStr + " - " + rollData.selectedCarac.label ); $(".table-resolution").remove(); game.data.RdDUtility.makeHTMLResolutionTable( $("#resolutionTable"), rollData.selectedCarac.value-2, parseInt(rollData.selectedCarac.value) + 2, -10, 11, rollData.selectedCarac.value, rollData.finalLevel ); } // Setup everything onload $(function() { // Set the default carac from the competence item rollData.selectedCarac = rollData.carac[rollData.competence.data.carac_defaut]; // Update html, according to data $("#carac").val( rollData.competence.data.carac_defaut ); $("#bonusmalus").val( rollData.bmValue ); updateRollResult(rollData); }); // Replace again the button action, as i overwritten it $('button').click((event) => { mydialog.data.actor.performRoll(rollData); }); // Update ! $('#bonusmalus').click((event) => { rollData.bmValue = event.currentTarget.value; // Update the selected bonus/malus //console.log("BM CLICKED !!!", rollData.bmValue, rollData.competence.data.niveau, parseInt(rollData.competence.data.niveau) + parseInt(rollData.bmValue) ); updateRollResult(rollData); }); $('#carac').click((event) => { let caracKey = event.currentTarget.value; rollData.selectedCarac = rollData.carac[caracKey]; // Update the selectedCarac //console.log("CARAC CLICKED !!!", rollData.selectedCarac, rollData.competence.data.niveau, rollData.bmValue); updateRollResult(rollData); }); } mydialog.render(true); } /* -------------------------------------------- */ /** @override */ getRollData() { const data = super.getRollData(); const shorthand = game.settings.get("foundryvtt-reve-de-dragon", "macroShorthand"); // Re-map all attributes onto the base roll data if ( !!shorthand ) { for ( let [k, v] of Object.entries(data.attributes) ) { if ( !(k in data) ) data[k] = v.value; } delete data.attributes; } // Map all items data using their slugified names data.items = this.data.items.reduce((obj, i) => { let key = i.name.slugify({strict: true}); let itemData = duplicate(i.data); if ( !!shorthand ) { for ( let [k, v] of Object.entries(itemData.attributes) ) { if ( !(k in itemData) ) itemData[k] = v.value; } delete itemData["attributes"]; } obj[key] = itemData; return obj; }, {}); return data; } }