import { L5rBaseDie } from "./dietype/l5r-base-die.js"; /** * Roll for L5R5e */ export class RollL5r5e extends Roll { static CHAT_TEMPLATE = "systems/l5r5e/templates/dice/chat-roll.html"; static TOOLTIP_TEMPLATE = "systems/l5r5e/templates/dice/tooltip.html"; // static CHAT_TEMPLATE = `${CONFIG.L5r5e.pathTemplates}dice/chat-roll.html`; // static TOOLTIP_TEMPLATE = `${CONFIG.L5r5e.pathTemplates}dice/tooltip.html`; constructor(...args) { console.log("RollL5r5e.in.args", args); // TODO tmp super(...args); this.l5r5e = { stance: "", skillId: "", actor: null, dicesTypes: { std: false, l5r: false, }, summary: { difficulty: 0, success_total: 0, success: 0, explosive: 0, opportunity: 0, strife: 0, }, }; // TODO parse difficulty stance skillId from cmd line ? console.log("RollL5r5e.out.args", args, this); // TODO tmp } /** * Execute the Roll, replacing dice and evaluating the total result * @override **/ evaluate({ minimize = false, maximize = false } = {}) { if (this._rolled) { throw new Error("This Roll object has already been rolled."); } // console.log('RollL5r5e.evaluate.in', this); return; // TODO tmp // Split L5R dices / regulars let l5rDices = this.terms.filter((term) => term instanceof L5rBaseDie); this.terms = this.terms.filter((t) => !(t instanceof L5rBaseDie)); this.terms = this._identifyTerms(this.constructor.cleanFormula(this.terms)); // Roll regular dices this._total = 0; if (this.terms.length > 0) { this.l5r5e.dicesTypes.std = true; console.log("this.terms", this.terms); // clean terms (trim symbols) this.terms = this._identifyTerms(this.constructor.cleanFormula(this.terms)); // Roll super.evaluate({ minimize, maximize }); } // Roll L5R dices if (l5rDices.length > 0) { this.l5r5e.dicesTypes.l5r = true; l5rDices.forEach((term) => { // Roll term.evaluate({ minimize, maximize }); // Total ["success", "explosive", "opportunity", "strife"].forEach((props) => { this.l5r5e.summary[props] += parseInt(term.l5r5e[props]); }); this.l5r5e.summary.success_total += parseInt(term.l5r5e.success) + parseInt(term.l5r5e.explosive); this.terms.push("+"); this.terms.push(term); }); // Clean if (this.terms[0] === "+") { this.terms.shift(); } // TODO Others advantage/disadvantage // re-inject L5R dices // this.terms = this.terms.concat(l5rTerms); } // Store final outputs //this._total = total; this._rolled = true; console.log("RollL5r5e.evaluate.out", this); // TODO tmp return this; } /** * Render the tooltip HTML for a Roll instance * @override */ getTooltip() { console.log("RollL5r5e.getTooltip", this); // TODO tmp const parts = this.dice .filter((t) => !(t instanceof L5rBaseDie)) .map((d) => { const cls = d.constructor; return { formula: d.formula, total: d.total, faces: d.faces, flavor: d.options.flavor, isL5rDices: d.constructor instanceof L5rBaseDie, rolls: d.results.map((r) => { return { result: cls.getResultLabel(r.result), classes: [ cls.name.toLowerCase(), "d" + d.faces, r.rerolled ? "rerolled" : null, r.exploded ? "exploded" : null, r.discarded ? "discarded" : null, r.result === 1 ? "min" : null, r.result === d.faces ? "max" : null, ] .filter((c) => !!c) .join(" "), }; }), }; }); parts.addedResults = this.addedResults; return renderTemplate(this.constructor.TOOLTIP_TEMPLATE, { parts }); } /** * Render a Roll instance to HTML * @override */ async render(chatOptions = {}) { console.log("RollL5r5e.render", chatOptions, this); // TODO tmp chatOptions = mergeObject( { user: game.user._id, flavor: null, template: this.constructor.CHAT_TEMPLATE, blind: false, }, chatOptions ); const isPrivate = chatOptions.isPrivate; // Execute the roll, if needed if (!this._rolled) { this.roll(); } // Define chat data const chatData = { formula: isPrivate ? "???" : this._formula, flavor: isPrivate ? null : chatOptions.flavor, user: chatOptions.user, isPublicRoll: !chatOptions.isPrivate, tooltip: isPrivate ? "" : await this.getTooltip(), total: isPrivate ? "?" : Math.round(this.total * 100) / 100, data: this.data, l5r5e: isPrivate ? {} : { dicesTypes: this.l5r5e.dicesTypes, summary: this.l5r5e.summary, dices: this.dice.map((d) => { return { diceTypeL5r: d instanceof L5rBaseDie, rolls: d.results.map((r) => { return { result: d.constructor.getResultLabel(r.result), }; }), }; }), }, }; console.log("RollL5r5e.render", chatOptions, chatData, this); // TODO tmp // Render the roll display template return renderTemplate(chatOptions.template, chatData); } /** * Transform a Roll instance into a ChatMessage, displaying the roll result. * This function can either create the ChatMessage directly, or return the data object that will be used to create. * @override */ toMessage(messageData = {}, { rollMode = null, create = true } = {}) { console.log("RollL5r5e.toMessage", this); // TODO tmp // Perform the roll, if it has not yet been rolled if (!this._rolled) { this.evaluate(); } const rMode = rollMode || messageData.rollMode || game.settings.get("core", "rollMode"); let template = CONST.CHAT_MESSAGE_TYPES.ROLL; if (["gmroll", "blindroll"].includes(rMode)) { messageData.whisper = ChatMessage.getWhisperRecipients("GM"); } if (rMode === "blindroll") messageData.blind = true; if (rMode === "selfroll") messageData.whisper = [game.user.id]; // Prepare chat data messageData = mergeObject( { user: game.user._id, type: template, content: this.total, sound: CONFIG.sounds.dice, }, messageData ); messageData.roll = this; // Prepare message options const messageOptions = { rollMode: rMode }; // Either create the message or just return the chat data return create ? CONFIG.ChatMessage.entityClass.create(messageData, messageOptions) : messageData; } /** @override */ static fromData(data) { const roll = super.fromData(data); roll.data = data.data; roll.l5r5e = data.l5r5e; console.log("RollL5r5e.fromData", roll); // TODO tmp return roll; } /** * Represent the data of the Roll as an object suitable for JSON serialization * @override */ toJSON() { const json = super.toJSON(); json.data = this.data; json.l5r5e = this.l5r5e; return json; } }