Seamless update for 20Q (deleted refresh button)
Fix for error css Some start for roll n keep
This commit is contained in:
@@ -90,7 +90,8 @@
|
|||||||
"difficulty": "TN",
|
"difficulty": "TN",
|
||||||
"difficulty_hidden": "TN ???",
|
"difficulty_hidden": "TN ???",
|
||||||
"dicepicker": "Dice Picker",
|
"dicepicker": "Dice Picker",
|
||||||
"void_point_used": "Void point used"
|
"void_point_used": "Void point used",
|
||||||
|
"roll_n_keep": "Roll & Keep"
|
||||||
},
|
},
|
||||||
"dicepicker": {
|
"dicepicker": {
|
||||||
"difficulty_title": "Difficulty",
|
"difficulty_title": "Difficulty",
|
||||||
@@ -100,6 +101,15 @@
|
|||||||
"roll_label": "Roll",
|
"roll_label": "Roll",
|
||||||
"bt_add_macro": "Add a macro"
|
"bt_add_macro": "Add a macro"
|
||||||
},
|
},
|
||||||
|
"roll_n_keep": {
|
||||||
|
"title": "L5R Roll & Keep",
|
||||||
|
"discard_drop_here": "Discard",
|
||||||
|
"reroll_drop_here": "Re-roll",
|
||||||
|
"reroll_chat": "Re-rolled dice",
|
||||||
|
"keep_drop_here": "Keep",
|
||||||
|
"keep_chat": "New roll from a exploding dice",
|
||||||
|
"bt_validate": "Finalize"
|
||||||
|
},
|
||||||
"max": "Max",
|
"max": "Max",
|
||||||
"current": "Current",
|
"current": "Current",
|
||||||
"quantity": "Quantity",
|
"quantity": "Quantity",
|
||||||
|
|||||||
@@ -90,7 +90,8 @@
|
|||||||
"difficulty": "TN",
|
"difficulty": "TN",
|
||||||
"difficulty_hidden": "TN ???",
|
"difficulty_hidden": "TN ???",
|
||||||
"dicepicker": "Dice Picker",
|
"dicepicker": "Dice Picker",
|
||||||
"void_point_used": "Void point used"
|
"void_point_used": "Void point used",
|
||||||
|
"roll_n_keep": "Roll & Keep"
|
||||||
},
|
},
|
||||||
"dicepicker": {
|
"dicepicker": {
|
||||||
"difficulty_title": "Difficulty",
|
"difficulty_title": "Difficulty",
|
||||||
@@ -100,6 +101,15 @@
|
|||||||
"roll_label": "Roll",
|
"roll_label": "Roll",
|
||||||
"bt_add_macro": "Add a macro"
|
"bt_add_macro": "Add a macro"
|
||||||
},
|
},
|
||||||
|
"roll_n_keep": {
|
||||||
|
"title": "L5R Roll & Keep",
|
||||||
|
"discard_drop_here": "Discard",
|
||||||
|
"reroll_drop_here": "Re-roll",
|
||||||
|
"reroll_chat": "Re-rolled dice",
|
||||||
|
"keep_drop_here": "Keep",
|
||||||
|
"keep_chat": "New roll from a exploding dice",
|
||||||
|
"bt_validate": "Finalize"
|
||||||
|
},
|
||||||
"max": "Max",
|
"max": "Max",
|
||||||
"current": "Actuales",
|
"current": "Actuales",
|
||||||
"quantity": "Cantidad",
|
"quantity": "Cantidad",
|
||||||
|
|||||||
@@ -90,7 +90,8 @@
|
|||||||
"difficulty": "ND",
|
"difficulty": "ND",
|
||||||
"difficulty_hidden": "ND ???",
|
"difficulty_hidden": "ND ???",
|
||||||
"dicepicker": "Dice Picker",
|
"dicepicker": "Dice Picker",
|
||||||
"void_point_used": "Point de vide utilisé"
|
"void_point_used": "Point de vide utilisé",
|
||||||
|
"roll_n_keep": "Roll & Keep"
|
||||||
},
|
},
|
||||||
"dicepicker": {
|
"dicepicker": {
|
||||||
"difficulty_title": "Difficulté",
|
"difficulty_title": "Difficulté",
|
||||||
@@ -100,6 +101,15 @@
|
|||||||
"roll_label": "Lancer",
|
"roll_label": "Lancer",
|
||||||
"bt_add_macro": "Ajouter une macro"
|
"bt_add_macro": "Ajouter une macro"
|
||||||
},
|
},
|
||||||
|
"roll_n_keep": {
|
||||||
|
"title": "L5R Roll & Keep",
|
||||||
|
"discard_drop_here": "Discard",
|
||||||
|
"reroll_drop_here": "Re-roll",
|
||||||
|
"reroll_chat": "Re-rolled dice",
|
||||||
|
"keep_drop_here": "Keep",
|
||||||
|
"keep_chat": "New roll from a exploding dice",
|
||||||
|
"bt_validate": "Finalize"
|
||||||
|
},
|
||||||
"max": "Max",
|
"max": "Max",
|
||||||
"current": "Actuel",
|
"current": "Actuel",
|
||||||
"quantity": "Quantité",
|
"quantity": "Quantité",
|
||||||
|
|||||||
@@ -48,24 +48,10 @@ export class TwentyQuestionsDialog extends FormApplication {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a refresh button on top of sheet
|
* Define a unique and dynamic element ID for the rendered ActorSheet application
|
||||||
* Allow a GM or player to see the change made by another player without closing the dialog
|
|
||||||
* @override
|
|
||||||
*/
|
*/
|
||||||
_getHeaderButtons() {
|
get id() {
|
||||||
let buttons = super._getHeaderButtons();
|
return `l5r5e-twenty-questions-dialog-${this.actor._id}`;
|
||||||
|
|
||||||
buttons.unshift({
|
|
||||||
label: game.i18n.localize("l5r5e.twenty_questions.bt_refresh"),
|
|
||||||
class: "twenty-questions",
|
|
||||||
icon: "fas fa-sync-alt",
|
|
||||||
onclick: async () => {
|
|
||||||
this._initialize(game.actors.get(this.actor._id));
|
|
||||||
await this._constructCache();
|
|
||||||
this.render(false);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return buttons;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -76,6 +62,18 @@ export class TwentyQuestionsDialog extends FormApplication {
|
|||||||
this._initialize(actor);
|
this._initialize(actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh data (used from socket)
|
||||||
|
*/
|
||||||
|
async refresh() {
|
||||||
|
if (!this.actor) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._initialize(game.actors.get(this.actor._id));
|
||||||
|
await this._constructCache();
|
||||||
|
this.render(false);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize actor and object for dialog
|
* Initialize actor and object for dialog
|
||||||
* @private
|
* @private
|
||||||
@@ -343,6 +341,9 @@ export class TwentyQuestionsDialog extends FormApplication {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Notify the change to other players
|
||||||
|
game.l5r5e.sockets.refreshAppId(this.id);
|
||||||
|
|
||||||
this.render(false);
|
this.render(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,13 +23,20 @@ export class L5rBaseDie extends DiceTerm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a string used as the label for each rolled result
|
* Return the full img string used as the label for each rolled result
|
||||||
* @override
|
* @override
|
||||||
*/
|
*/
|
||||||
static getResultLabel(result) {
|
static getResultLabel(result) {
|
||||||
return `<img src="${CONFIG.l5r5e.paths.assets}dices/default/${this.FACES[result].image}.svg" alt="${result}" />`;
|
return `<img src="${CONFIG.l5r5e.paths.assets}dices/default/${this.FACES[result].image}.svg" alt="${result}" />`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the url of the result face
|
||||||
|
*/
|
||||||
|
static getResultSrc(result) {
|
||||||
|
return `${CONFIG.l5r5e.paths.assets}dices/default/${this.FACES[result].image}.svg`;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the total result of the DiceTerm if it has been evaluated
|
* Return the total result of the DiceTerm if it has been evaluated
|
||||||
* Always zero for L5R dices to not count in total for regular dices
|
* Always zero for L5R dices to not count in total for regular dices
|
||||||
|
|||||||
330
system/scripts/dice/roll-n-keep-dialog.js
Normal file
330
system/scripts/dice/roll-n-keep-dialog.js
Normal file
@@ -0,0 +1,330 @@
|
|||||||
|
/**
|
||||||
|
* L5R Dice Roll n Keep dialog
|
||||||
|
* @extends {FormApplication}
|
||||||
|
*/
|
||||||
|
export class RollnKeepDialog extends FormApplication {
|
||||||
|
/**
|
||||||
|
* Player choice list
|
||||||
|
*/
|
||||||
|
static CHOICES = {
|
||||||
|
discard: "discard",
|
||||||
|
face_change: "face-change",
|
||||||
|
keep: "keep",
|
||||||
|
nothing: null,
|
||||||
|
reroll: "reroll",
|
||||||
|
reserve: "reserve",
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current ChatMessage where we come from
|
||||||
|
* @param {ChatMessage} message
|
||||||
|
*/
|
||||||
|
message = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Payload Object
|
||||||
|
*/
|
||||||
|
object = {
|
||||||
|
dicesList: [[]],
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assign the default options
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
static get defaultOptions() {
|
||||||
|
return mergeObject(super.defaultOptions, {
|
||||||
|
id: "l5r5e-roll-n-keep-dialog",
|
||||||
|
classes: ["l5r5e", "roll-n-keep-dialog"],
|
||||||
|
template: CONFIG.l5r5e.paths.templates + "dice/roll-n-keep-dialog.html",
|
||||||
|
title: game.i18n.localize("l5r5e.roll_n_keep.title"),
|
||||||
|
width: 660,
|
||||||
|
height: 660,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define a unique and dynamic element ID for the rendered ActorSheet application
|
||||||
|
*/
|
||||||
|
get id() {
|
||||||
|
return `l5r5e-roll-n-keep-dialog-${this.message._id}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the Roll n Keep dialog
|
||||||
|
* @param {ChatMessage} message
|
||||||
|
* @param {FormApplicationOptions} options
|
||||||
|
*/
|
||||||
|
constructor(message, options = {}) {
|
||||||
|
super({}, options);
|
||||||
|
this.message = message;
|
||||||
|
this._initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh data (used from socket)
|
||||||
|
*/
|
||||||
|
async refresh() {
|
||||||
|
if (!this.message) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._initialize();
|
||||||
|
this.render(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the dialog with the message
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_initialize() {
|
||||||
|
// Get the roll
|
||||||
|
const roll = game.l5r5e.RollL5r5e.fromData(this.message.roll);
|
||||||
|
|
||||||
|
console.clear();
|
||||||
|
console.log(roll); // TODO TMP
|
||||||
|
|
||||||
|
// Already history
|
||||||
|
if (Array.isArray(roll.l5r5e.history)) {
|
||||||
|
this.object.dicesList = roll.l5r5e.history;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// New
|
||||||
|
roll.terms.forEach((term) => {
|
||||||
|
if (typeof term !== "object") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
term.results.forEach((res) => {
|
||||||
|
this.object.dicesList[0].push({
|
||||||
|
type: term.constructor.name,
|
||||||
|
face: res.result,
|
||||||
|
explosive: term.constructor.FACES[res.result].explosive,
|
||||||
|
img: term.constructor.getResultSrc(res.result),
|
||||||
|
choice: RollnKeepDialog.CHOICES.nothing,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create drag-and-drop workflow handlers for this Application
|
||||||
|
* @return An array of DragDrop handlers
|
||||||
|
*/
|
||||||
|
_createDragDropHandlers() {
|
||||||
|
return [
|
||||||
|
new DragDrop({
|
||||||
|
dragSelector: ".dice.draggable",
|
||||||
|
dropSelector: ".dropbox",
|
||||||
|
permissions: { dragstart: this._canDragStart.bind(this), drop: this._canDragDrop.bind(this) },
|
||||||
|
callbacks: { dragstart: this._onDragStart.bind(this), drop: this._onDropItem.bind(this) },
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback actions which occur at the beginning of a drag start workflow.
|
||||||
|
* @param {DragEvent} event The originating DragEvent
|
||||||
|
*/
|
||||||
|
_onDragStart(event) {
|
||||||
|
const target = $(event.currentTarget);
|
||||||
|
event.dataTransfer.setData(
|
||||||
|
"text/plain",
|
||||||
|
JSON.stringify({
|
||||||
|
step: target.data("step"),
|
||||||
|
die: target.data("die"),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct and return the data object used to render the HTML template for this form application.
|
||||||
|
* @param options
|
||||||
|
* @return {Object}
|
||||||
|
*/
|
||||||
|
getData(options = null) {
|
||||||
|
const draggableList = [];
|
||||||
|
this.object.dicesList.forEach((step, idx) => {
|
||||||
|
step.forEach((die, dieNum) => {
|
||||||
|
if (die) {
|
||||||
|
draggableList[dieNum] = idx;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
...super.getData(options),
|
||||||
|
data: this.object,
|
||||||
|
draggableList: draggableList,
|
||||||
|
l5r5e: this.message._roll.l5r5e,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen to html elements
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
activateListeners(html) {
|
||||||
|
super.activateListeners(html);
|
||||||
|
|
||||||
|
// Finalize Button
|
||||||
|
html.find("#finalize").on("click", (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
if (this._getKeepCount() > 0) {
|
||||||
|
this.submit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle dropped items
|
||||||
|
*/
|
||||||
|
async _onDropItem(event) {
|
||||||
|
const type = $(event.currentTarget).data("type");
|
||||||
|
const json = event.dataTransfer.getData("text/plain");
|
||||||
|
if (!json || !Object.values(RollnKeepDialog.CHOICES).some((e) => !!e && e === type)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = JSON.parse(json);
|
||||||
|
if (!data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let addNewRoll = false;
|
||||||
|
const current = this.object.dicesList[data.step][data.die];
|
||||||
|
current.choice = type;
|
||||||
|
|
||||||
|
// Actions p 26 : change, ignore/discard, reroll, reserve, change face
|
||||||
|
switch (type) {
|
||||||
|
case RollnKeepDialog.CHOICES.keep:
|
||||||
|
if (current.explosive) {
|
||||||
|
addNewRoll = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RollnKeepDialog.CHOICES.reroll:
|
||||||
|
addNewRoll = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// New roll
|
||||||
|
if (addNewRoll) {
|
||||||
|
if (!this.object.dicesList[data.step + 1]) {
|
||||||
|
this.object.dicesList[data.step + 1] = Array(this.object.dicesList[0].length).fill(null);
|
||||||
|
}
|
||||||
|
this.object.dicesList[data.step + 1][data.die] = await this._newRoll(current.type, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.render(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Roll a new die avec return the result
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
async _newRoll(dieType, actionType) {
|
||||||
|
const roll = await new game.l5r5e.RollL5r5e(dieType === "RingDie" ? "1dr" : "1ds");
|
||||||
|
roll.actor = this.message.roll.l5r5e.actor;
|
||||||
|
roll.l5r5e.stance = this.message.roll.l5r5e.stance;
|
||||||
|
// roll.l5r5e.skillId = this.message.roll.l5r5e.skillId;
|
||||||
|
// roll.l5r5e.skillCatId = this.message.roll.l5r5e.skillCatId;
|
||||||
|
|
||||||
|
await roll.roll();
|
||||||
|
await roll.toMessage({
|
||||||
|
flavor: game.i18n.localize(`l5r5e.roll_n_keep.${actionType}_chat`),
|
||||||
|
});
|
||||||
|
|
||||||
|
const dice = roll.terms[0];
|
||||||
|
const result = dice.results[0].result;
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: dieType,
|
||||||
|
face: result,
|
||||||
|
explosive: dice.constructor.FACES[result].explosive,
|
||||||
|
img: dice.constructor.getResultSrc(result),
|
||||||
|
choice: RollnKeepDialog.CHOICES.nothing,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the current number of dices kept
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_getKeepCount() {
|
||||||
|
return this.object.dicesList.reduce((acc, step) => {
|
||||||
|
return (
|
||||||
|
acc +
|
||||||
|
step.reduce((acc2, die) => {
|
||||||
|
if (!!die && die.choice === RollnKeepDialog.CHOICES.keep) {
|
||||||
|
acc2 = acc2 + 1;
|
||||||
|
}
|
||||||
|
return acc2;
|
||||||
|
}, 0)
|
||||||
|
);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called upon form submission after form data is validated
|
||||||
|
* @param event The initial triggering submission event
|
||||||
|
* @param formData The object of validated form data with which to update the object
|
||||||
|
* @returns A Promise which resolves once the update operation has completed
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
async _updateObject(event, formData) {
|
||||||
|
console.log("**** _updateObject");
|
||||||
|
|
||||||
|
// Notify the change to other players
|
||||||
|
// game.l5r5e.sockets.refreshAppId(this.id);
|
||||||
|
|
||||||
|
// this.message._roll.l5r5e.history = {test: "yahooo"};
|
||||||
|
|
||||||
|
// await message.update({
|
||||||
|
// data: {
|
||||||
|
// roll: roll
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// message.render(false);
|
||||||
|
|
||||||
|
// console.log(roll.toJSON(), this.message);
|
||||||
|
|
||||||
|
// ui.chat.updateMessage(message);
|
||||||
|
// ui.chat.postOne(message, false);
|
||||||
|
|
||||||
|
// if (game.user.isGM) {
|
||||||
|
// message.delete();
|
||||||
|
// } else {
|
||||||
|
// game.l5r5e.sockets.deleteChatMessage(messageId);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return this.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle execution of a chat card action via a click event on the RnK button
|
||||||
|
* @param {Event} event The originating click event
|
||||||
|
* @returns {Promise} A promise which resolves once the handler workflow is complete
|
||||||
|
*/
|
||||||
|
static async onChatAction(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
// Extract card data
|
||||||
|
const button = $(event.currentTarget);
|
||||||
|
button.attr("disabled", true);
|
||||||
|
const card = button.parents(".l5r5e.item-display.dices-l5r");
|
||||||
|
const messageId = card.parents(".chat-message").data("message-id");
|
||||||
|
const message = game.messages.get(messageId);
|
||||||
|
|
||||||
|
// Validate permission to proceed with the roll n keep
|
||||||
|
if (!message || !message._roll.l5r5e.actor.owner) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
new RollnKeepDialog(message).render(true);
|
||||||
|
|
||||||
|
// Re-enable the button
|
||||||
|
button.attr("disabled", false);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { L5rBaseDie } from "./dietype/l5r-base-die.js";
|
import { L5rBaseDie } from "./dietype/l5r-base-die.js";
|
||||||
|
import { ActorL5r5e } from "../actor.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Roll for L5R5e
|
* Roll for L5R5e
|
||||||
@@ -20,14 +21,15 @@ export class RollL5r5e extends Roll {
|
|||||||
l5r: false,
|
l5r: false,
|
||||||
},
|
},
|
||||||
summary: {
|
summary: {
|
||||||
difficulty: 0,
|
difficulty: 2,
|
||||||
difficultyHidden: false,
|
difficultyHidden: false,
|
||||||
|
voidPointUsed: false,
|
||||||
success: 0,
|
success: 0,
|
||||||
explosive: 0,
|
explosive: 0,
|
||||||
opportunity: 0,
|
opportunity: 0,
|
||||||
strife: 0,
|
strife: 0,
|
||||||
voidPointUsed: false,
|
|
||||||
},
|
},
|
||||||
|
history: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parse flavor for stance and skillId
|
// Parse flavor for stance and skillId
|
||||||
@@ -198,9 +200,15 @@ export class RollL5r5e extends Roll {
|
|||||||
this.roll();
|
this.roll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const canRnK = false; // TODO TMP dev in progress
|
||||||
|
// const canRnK = !this.l5r5e.dicesTypes.std
|
||||||
|
// && this.l5r5e.dicesTypes.l5r
|
||||||
|
// && this.dice.length > 1
|
||||||
|
// && this.l5r5e.actor // pb with dice with no actor
|
||||||
|
// && this.l5r5e.actor.owner;
|
||||||
|
|
||||||
// Define chat data
|
// Define chat data
|
||||||
const chatData = {
|
const chatData = {
|
||||||
// borderColor: game.user.color, // don't work :/
|
|
||||||
formula: isPrivate ? "???" : this._formula,
|
formula: isPrivate ? "???" : this._formula,
|
||||||
flavor: isPrivate ? null : chatOptions.flavor,
|
flavor: isPrivate ? null : chatOptions.flavor,
|
||||||
user: chatOptions.user,
|
user: chatOptions.user,
|
||||||
@@ -212,6 +220,7 @@ export class RollL5r5e extends Roll {
|
|||||||
? {}
|
? {}
|
||||||
: {
|
: {
|
||||||
...this.l5r5e,
|
...this.l5r5e,
|
||||||
|
canRnK: canRnK,
|
||||||
dices: this.dice.map((d) => {
|
dices: this.dice.map((d) => {
|
||||||
return {
|
return {
|
||||||
diceTypeL5r: d instanceof L5rBaseDie,
|
diceTypeL5r: d instanceof L5rBaseDie,
|
||||||
@@ -277,8 +286,16 @@ export class RollL5r5e extends Roll {
|
|||||||
static fromData(data) {
|
static fromData(data) {
|
||||||
const roll = super.fromData(data);
|
const roll = super.fromData(data);
|
||||||
|
|
||||||
roll.data = data.data;
|
roll.data = duplicate(data.data);
|
||||||
roll.l5r5e = data.l5r5e;
|
roll.l5r5e = duplicate(data.l5r5e);
|
||||||
|
|
||||||
|
// get real Actor object
|
||||||
|
if (data.l5r5e.actor && !(data.l5r5e.actor instanceof ActorL5r5e)) {
|
||||||
|
const actor = game.actors.get(data.l5r5e.actor.id);
|
||||||
|
if (actor) {
|
||||||
|
roll.l5r5e.actor = actor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return roll;
|
return roll;
|
||||||
}
|
}
|
||||||
@@ -290,8 +307,15 @@ export class RollL5r5e extends Roll {
|
|||||||
toJSON() {
|
toJSON() {
|
||||||
const json = super.toJSON();
|
const json = super.toJSON();
|
||||||
|
|
||||||
json.data = this.data;
|
json.data = duplicate(this.data);
|
||||||
json.l5r5e = this.l5r5e;
|
json.l5r5e = duplicate(this.l5r5e);
|
||||||
|
|
||||||
|
// lightweight the Actor
|
||||||
|
if (json.l5r5e.actor) {
|
||||||
|
json.l5r5e.actor = {
|
||||||
|
id: json.l5r5e.actor._id,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Import Commons Modules
|
// Import Commons Modules
|
||||||
import { L5R5E } from "./config.js";
|
import { L5R5E } from "./config.js";
|
||||||
import { HelpersL5r5e } from "./helpers.js";
|
import { HelpersL5r5e } from "./helpers.js";
|
||||||
|
import { SocketHandlerL5r5e } from "./socket-handler.js";
|
||||||
import { RegisterSettings } from "./settings.js";
|
import { RegisterSettings } from "./settings.js";
|
||||||
import { PreloadTemplates } from "./preloadTemplates.js";
|
import { PreloadTemplates } from "./preloadTemplates.js";
|
||||||
import { HelpDialog } from "./help/help-dialog.js";
|
import { HelpDialog } from "./help/help-dialog.js";
|
||||||
@@ -13,6 +14,7 @@ import { AbilityDie } from "./dice/dietype/ability-die.js";
|
|||||||
import { RingDie } from "./dice/dietype/ring-die.js";
|
import { RingDie } from "./dice/dietype/ring-die.js";
|
||||||
import { RollL5r5e } from "./dice/roll.js";
|
import { RollL5r5e } from "./dice/roll.js";
|
||||||
import { DicePickerDialog } from "./dice/dice-picker-dialog.js";
|
import { DicePickerDialog } from "./dice/dice-picker-dialog.js";
|
||||||
|
import { RollnKeepDialog } from "./dice/roll-n-keep-dialog.js";
|
||||||
// Items
|
// Items
|
||||||
import { ItemL5r5e } from "./item.js";
|
import { ItemL5r5e } from "./item.js";
|
||||||
import { ItemSheetL5r5e } from "./items/item-sheet.js";
|
import { ItemSheetL5r5e } from "./items/item-sheet.js";
|
||||||
@@ -59,12 +61,14 @@ Hooks.once("init", async function () {
|
|||||||
CONFIG.Dice.terms["s"] = AbilityDie;
|
CONFIG.Dice.terms["s"] = AbilityDie;
|
||||||
CONFIG.Dice.terms["r"] = RingDie;
|
CONFIG.Dice.terms["r"] = RingDie;
|
||||||
|
|
||||||
// Add some helper classes in game
|
// Add some classes in game
|
||||||
game.l5r5e = {
|
game.l5r5e = {
|
||||||
HelpersL5r5e,
|
HelpersL5r5e,
|
||||||
RollL5r5e,
|
RollL5r5e,
|
||||||
DicePickerDialog,
|
DicePickerDialog,
|
||||||
|
RollnKeepDialog,
|
||||||
HelpDialog,
|
HelpDialog,
|
||||||
|
sockets: new SocketHandlerL5r5e(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Register custom system settings
|
// Register custom system settings
|
||||||
@@ -223,6 +227,7 @@ Hooks.on("renderChatMessage", (message, html, data) => {
|
|||||||
// Add a extra CSS class to roll
|
// Add a extra CSS class to roll
|
||||||
if (message.isRoll) {
|
if (message.isRoll) {
|
||||||
html.addClass("roll");
|
html.addClass("roll");
|
||||||
|
html.on("click", ".chat-dice-rnk", RollnKeepDialog.onChatAction.bind(this));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
71
system/scripts/socket-handler.js
Normal file
71
system/scripts/socket-handler.js
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
/**
|
||||||
|
* L5R Socket Handler
|
||||||
|
*/
|
||||||
|
export class SocketHandlerL5r5e {
|
||||||
|
/**
|
||||||
|
* Namespace in FVTT
|
||||||
|
*/
|
||||||
|
static SOCKET_NAME = "system.l5r5e";
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.registerSocketListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* registers all the socket listeners
|
||||||
|
*/
|
||||||
|
registerSocketListeners() {
|
||||||
|
game.socket.on(SocketHandlerL5r5e.SOCKET_NAME, (data) => {
|
||||||
|
switch (data.type) {
|
||||||
|
case "deleteChatMessage":
|
||||||
|
this._onDeleteChatMessage(data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "refreshAppId":
|
||||||
|
this._onRefreshAppId(data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
console.warn(new Error("This socket event is not supported"), data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteChatMessage(messageId) {
|
||||||
|
game.socket.emit(SocketHandlerL5r5e.SOCKET_NAME, {
|
||||||
|
type: "deleteChatMessage",
|
||||||
|
messageId,
|
||||||
|
userId: game.userId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_onDeleteChatMessage(data) {
|
||||||
|
const message = game.messages.get(data.messageId);
|
||||||
|
// only delete the message if the user is a GM and the event emitter is one of the recipients
|
||||||
|
if (game.user.isGM && message.data["whisper"].includes(data.userId)) {
|
||||||
|
message.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh a app by it's id, not windowsId (ex "l5r5e-twenty-questions-dialog-kZHczAFghMNYFRWe", not "65")
|
||||||
|
* usage : game.l5r5e.sockets.refreshAppId(appId);
|
||||||
|
* @param appId
|
||||||
|
*/
|
||||||
|
refreshAppId(appId) {
|
||||||
|
game.socket.emit(SocketHandlerL5r5e.SOCKET_NAME, {
|
||||||
|
type: "refreshAppId",
|
||||||
|
appId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_onRefreshAppId(data) {
|
||||||
|
const app = Object.values(ui.windows).find((e) => e.id === data.appId);
|
||||||
|
if (!app) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (typeof app.refresh !== "function") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
app.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
@@ -143,3 +143,44 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.roll-n-keep-dialog {
|
||||||
|
img {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profil {
|
||||||
|
border-bottom: 1px solid #782e22;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropbox {
|
||||||
|
min-height: 100px;
|
||||||
|
|
||||||
|
&.discards {
|
||||||
|
border: 1px solid gray;
|
||||||
|
}
|
||||||
|
&.rerolls {
|
||||||
|
border: 1px solid orangered;
|
||||||
|
}
|
||||||
|
&.keeps {
|
||||||
|
border: 1px solid green;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dice {
|
||||||
|
height: 40px;
|
||||||
|
width: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.discard {
|
||||||
|
filter: opacity(0.5);
|
||||||
|
border: 3px solid gray;
|
||||||
|
}
|
||||||
|
.reroll {
|
||||||
|
filter: opacity(0.5);
|
||||||
|
border: 3px solid orangered;
|
||||||
|
}
|
||||||
|
.keep {
|
||||||
|
border: 3px solid green;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,6 +11,18 @@
|
|||||||
padding: 0.25rem;
|
padding: 0.25rem;
|
||||||
border-bottom: 0 none;
|
border-bottom: 0 none;
|
||||||
}
|
}
|
||||||
|
.errors {
|
||||||
|
position: sticky;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
z-index: 999;
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
background-color: $l5r5e-red;
|
||||||
|
border: 1px solid $dark-red;
|
||||||
|
border-radius: 1rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
h3 {
|
h3 {
|
||||||
font-size: 1.25rem;
|
font-size: 1.25rem;
|
||||||
color: $l5r5e-label;
|
color: $l5r5e-label;
|
||||||
@@ -128,18 +140,6 @@
|
|||||||
.dropbox {
|
.dropbox {
|
||||||
min-height: 75px;
|
min-height: 75px;
|
||||||
}
|
}
|
||||||
.errors {
|
|
||||||
position: sticky;
|
|
||||||
top: 0px;
|
|
||||||
left: 0px;
|
|
||||||
z-index: 999;
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
background-color: $l5r5e-red;
|
|
||||||
border: 1px solid $dark-red;
|
|
||||||
border-radius: 1rem;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
.checklist {
|
.checklist {
|
||||||
margin: 0.25rem 0.25rem 1rem;
|
margin: 0.25rem 0.25rem 1rem;
|
||||||
strong {
|
strong {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
button {
|
button {
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
|
cursor: url("../assets/cursors/pointer.webp"), pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// sidebar
|
// sidebar
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
"version": "0.5.1",
|
"version": "0.5.1",
|
||||||
"minimumCoreVersion": "0.7.9",
|
"minimumCoreVersion": "0.7.9",
|
||||||
"compatibleCoreVersion": "0.7.9",
|
"compatibleCoreVersion": "0.7.9",
|
||||||
|
"socket": true,
|
||||||
"author": "Team L5R",
|
"author": "Team L5R",
|
||||||
"background": "L5R-Header.webp",
|
"background": "L5R-Header.webp",
|
||||||
"scripts": [],
|
"scripts": [],
|
||||||
|
|||||||
@@ -43,7 +43,6 @@
|
|||||||
<div class="l5r5e dice-formula">{{formula}}</div>
|
<div class="l5r5e dice-formula">{{formula}}</div>
|
||||||
|
|
||||||
<div class="l5r5e dice-result">
|
<div class="l5r5e dice-result">
|
||||||
|
|
||||||
{{#if l5r5e.dicesTypes.l5r}}
|
{{#if l5r5e.dicesTypes.l5r}}
|
||||||
<div class="l5r5e item-display dices-l5r">
|
<div class="l5r5e item-display dices-l5r">
|
||||||
{{#each l5r5e.dices}}
|
{{#each l5r5e.dices}}
|
||||||
@@ -54,7 +53,10 @@
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
||||||
<!-- TODO add Button for Roll & Keep dialog -->
|
{{!-- Roll & Keep Button --}}
|
||||||
|
{{#if l5r5e.canRnK}}
|
||||||
|
<button class="l5r5e chat-dice-rnk">{{localize "l5r5e.chatdices.roll_n_keep"}}</button>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
{{#l5r5e.summary}}
|
{{#l5r5e.summary}}
|
||||||
<ul>
|
<ul>
|
||||||
@@ -77,7 +79,6 @@
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#if l5r5e.dicesTypes.std}}
|
{{#if l5r5e.dicesTypes.std}}
|
||||||
|
|
||||||
<div class="l5r5e dices-std">
|
<div class="l5r5e dices-std">
|
||||||
{{#each results}}
|
{{#each results}}
|
||||||
{{#each this.rolls}}
|
{{#each this.rolls}}
|
||||||
|
|||||||
90
system/templates/dice/roll-n-keep-dialog.html
Normal file
90
system/templates/dice/roll-n-keep-dialog.html
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<form class="l5r5e roll-n-keep-dialog" autocomplete="off">
|
||||||
|
|
||||||
|
{{!-- Profil --}}
|
||||||
|
<div class="l5r5e profil">
|
||||||
|
<header class="part-header flexrow chat-profil">
|
||||||
|
<span class="chat-profil-element">
|
||||||
|
<img class="profile-img"
|
||||||
|
src="{{#if l5r5e.actor.img}}{{l5r5e.actor.img}}{{else}}icons/svg/mystery-man.svg{{/if}}"
|
||||||
|
data-edit="img"
|
||||||
|
height="40"
|
||||||
|
width="40"
|
||||||
|
alt="{{#if l5r5e.actor.name}}{{l5r5e.actor.name}}{{else}}mystery-man{{/if}}"
|
||||||
|
>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="chat-profil-element">
|
||||||
|
<i class="chat-profil-stance {{l5r5e.stance}} i_{{l5r5e.stance}}" title="{{localizeRing l5r5e.stance}}"></i>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="chat-profil-element-skill">
|
||||||
|
{{#if l5r5e.skillId}}
|
||||||
|
{{localizeSkillId l5r5e.skillId}}
|
||||||
|
{{else}}
|
||||||
|
{{#if l5r5e.skillCatId}}{{localizeSkill l5r5e.skillCatId 'title'}}{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="chat-profil-element">
|
||||||
|
{{#if l5r5e.summary.difficultyHidden}}
|
||||||
|
{{localize 'l5r5e.chatdices.difficulty_hidden'}}
|
||||||
|
{{else}}
|
||||||
|
{{localize 'l5r5e.chatdices.difficulty'}} {{l5r5e.summary.difficulty}}
|
||||||
|
{{/if}}
|
||||||
|
{{#if l5r5e.summary.voidPointUsed}}
|
||||||
|
<br><i class="i_void" title="{{localize 'l5r5e.chatdices.void_point_used'}}"></i>
|
||||||
|
{{/if}}
|
||||||
|
</span>
|
||||||
|
</header>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{!-- Discard & ReRoll --}}
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<fieldset class="dropbox discards" data-type="discard">
|
||||||
|
<legend class="section-header"><i class="fa fa-arrow-down" aria-hidden="true"></i> {{ localize 'l5r5e.roll_n_keep.discard_drop_here' }}</legend>
|
||||||
|
</fieldset>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<fieldset class="dropbox rerolls" data-type="reroll">
|
||||||
|
<legend class="section-header"><i class="fa fa-arrow-down" aria-hidden="true"></i> {{ localize 'l5r5e.roll_n_keep.reroll_drop_here' }}</legend>
|
||||||
|
</fieldset>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{{!-- DiceList history --}}
|
||||||
|
<table>
|
||||||
|
{{#each data.dicesList as |item idxStep|}}
|
||||||
|
<tr>
|
||||||
|
{{#each item as |dice idxDie|}}
|
||||||
|
<td>
|
||||||
|
<div class="dice {{this.choice}} {{#ifCond (lookup ../../draggableList idxDie) '==' idxStep }}draggable{{/ifCond}}" data-step="{{idxStep}}" data-die="{{idxDie}}">
|
||||||
|
{{#if this.img}}
|
||||||
|
<img src="{{this.img}}" alt="{{idxStep}}_{{idxDie}}" />
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
{{/each}}
|
||||||
|
</tr>
|
||||||
|
{{/each}}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{{!-- Keep --}}
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<fieldset class="dropbox keeps" data-type="keep">
|
||||||
|
<legend class="section-header"><i class="fa fa-arrow-down" aria-hidden="true"></i> {{ localize 'l5r5e.roll_n_keep.keep_drop_here' }}</legend>
|
||||||
|
</fieldset>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<button id="finalize" name="finalize" type="button">{{ localize 'l5r5e.roll_n_keep.bt_validate' }} <i class='fas fa-arrow-circle-right'></i></button>
|
||||||
|
|
||||||
|
</form>
|
||||||
Reference in New Issue
Block a user