Merge branch 'gm_toolbox_monitor_application_v2' into 'dev'
ApplicationV2 GM Toolbox and GM Monitor See merge request teaml5r/l5r5e!37
This commit is contained in:
@@ -117,7 +117,6 @@ export class ActorL5r5e extends Actor {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now using updateDocuments
|
|
||||||
return Actor.updateDocuments([docData], context).then(() => {
|
return Actor.updateDocuments([docData], context).then(() => {
|
||||||
// Notify the "Gm Monitor" if this actor is watched
|
// Notify the "Gm Monitor" if this actor is watched
|
||||||
if (game.settings.get(CONFIG.l5r5e.namespace, "gm-monitor-actors").some((uuid) => uuid === this.uuid)) {
|
if (game.settings.get(CONFIG.l5r5e.namespace, "gm-monitor-actors").some((uuid) => uuid === this.uuid)) {
|
||||||
|
|||||||
@@ -792,7 +792,7 @@ export class RollnKeepDialog extends FormApplication {
|
|||||||
const messageId = card.parents(".chat-message").data("message-id");
|
const messageId = card.parents(".chat-message").data("message-id");
|
||||||
|
|
||||||
// Already open ? close it
|
// Already open ? close it
|
||||||
const app = Object.values(ui.windows).find((e) => e.id === `l5r5e-roll-n-keep-dialog-${messageId}`);
|
const app = game.l5r5e.HelpersL5r5e.getApplication(`l5r5e-roll-n-keep-dialog-${messageId}`);
|
||||||
if (app) {
|
if (app) {
|
||||||
app.close();
|
app.close();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,201 +1,142 @@
|
|||||||
/**
|
|
||||||
* L5R GM Monitor Windows
|
const HandlebarsApplicationMixin = foundry.applications.api.HandlebarsApplicationMixin;
|
||||||
* @extends {FormApplication}
|
const ApplicationV2 = foundry.applications.api.ApplicationV2;
|
||||||
*/
|
export class GmMonitor extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||||
export class GmMonitor extends FormApplication {
|
/** @override ApplicationV2 */
|
||||||
/**
|
static get DEFAULT_OPTIONS() {
|
||||||
* Settings
|
return {
|
||||||
*/
|
id: "l5r5e-gm-monitor",
|
||||||
object = {
|
tag: "div",
|
||||||
view: "characters", // characters|armies
|
window: {
|
||||||
actors: [],
|
contentClasses: ["l5r5e", "gm-monitor"],
|
||||||
|
title: "l5r5e.gm.monitor.title",
|
||||||
|
minimizable: true,
|
||||||
|
controls: [
|
||||||
|
{
|
||||||
|
label: game.i18n.localize("l5r5e.gm.monitor.add_selected_tokens"),
|
||||||
|
icon: "fas fa-users",
|
||||||
|
action: "add_selected_tokens",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: game.i18n.localize("l5r5e.gm.monitor.switch_view"),
|
||||||
|
icon: "fas fa-repeat",
|
||||||
|
action: "change_view_tab"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
resizable: true,
|
||||||
|
editable: true,
|
||||||
|
},
|
||||||
|
position: {
|
||||||
|
width: "600",
|
||||||
|
height: "150"
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
add_selected_tokens: GmMonitor.#addSelectedTokens,
|
||||||
|
change_view_tab: GmMonitor.#rotateViewTab,
|
||||||
|
remove_actor: GmMonitor.#removeActor,
|
||||||
|
toggle_prepared: GmMonitor.#togglePrepared,
|
||||||
|
change_stance: {
|
||||||
|
buttons: [0, 2],
|
||||||
|
handler: GmMonitor.#changeStance,
|
||||||
|
},
|
||||||
|
modify_fatigue: {
|
||||||
|
buttons: [0, 1, 2],
|
||||||
|
handler: GmMonitor.#modifyFatigue,
|
||||||
|
},
|
||||||
|
modify_strife: {
|
||||||
|
buttons: [0, 1, 2],
|
||||||
|
handler: GmMonitor.#modifyStrife,
|
||||||
|
},
|
||||||
|
modify_voidPoint: {
|
||||||
|
buttons: [0, 1, 2],
|
||||||
|
handler: GmMonitor.#modifyVoidPoint,
|
||||||
|
},
|
||||||
|
modify_casualties: {
|
||||||
|
buttons: [0, 1, 2],
|
||||||
|
handler: GmMonitor.#modifyCasualties,
|
||||||
|
},
|
||||||
|
modify_panic: {
|
||||||
|
buttons: [0, 1, 2],
|
||||||
|
handler: GmMonitor.#modifyPanic,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dragDrop: [{ dragSelector: null, dropSelector: null }],
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @override HandlebarsApplicationMixin */
|
||||||
|
static PARTS = {
|
||||||
|
hidden_tabs: {
|
||||||
|
template: "templates/generic/tab-navigation.hbs"
|
||||||
|
},
|
||||||
|
character: {
|
||||||
|
id: "character",
|
||||||
|
template: "systems/l5r5e/templates/" + "gm/monitor/character-view.html"
|
||||||
|
},
|
||||||
|
army: {
|
||||||
|
if: "army",
|
||||||
|
template: "systems/l5r5e/templates/" + "gm/monitor/army-view.html"
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assign the default options
|
* @type {Record<string, string>}
|
||||||
* @override
|
* @override ApplicationV2
|
||||||
*/
|
*/
|
||||||
static get defaultOptions() {
|
tabGroups = {
|
||||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
view: "character"
|
||||||
id: "l5r5e-gm-monitor",
|
};
|
||||||
classes: ["l5r5e", "gm-monitor"],
|
|
||||||
template: CONFIG.l5r5e.paths.templates + "gm/gm-monitor.html",
|
/**
|
||||||
title: game.i18n.localize("l5r5e.gm.monitor.title"),
|
* Data that is pushed to html
|
||||||
width: 800,
|
*/
|
||||||
height: 300,
|
context = {
|
||||||
resizable: true,
|
actors: []
|
||||||
closeOnSubmit: false,
|
|
||||||
submitOnClose: false,
|
|
||||||
submitOnChange: false,
|
|
||||||
dragDrop: [{ dragSelector: null, dropSelector: null }],
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the Switch View button on top of sheet
|
* hooks we act upon, saved since we need to remove them when this window is not open
|
||||||
* @override
|
|
||||||
*/
|
*/
|
||||||
_getHeaderButtons() {
|
#hooks = [];
|
||||||
let buttons = super._getHeaderButtons();
|
|
||||||
|
|
||||||
// Switch view Characters/Armies
|
|
||||||
buttons.unshift({
|
|
||||||
label: game.i18n.localize("l5r5e.gm.monitor.switch_view"),
|
|
||||||
class: "switch-view",
|
|
||||||
icon: "fas fa-repeat",
|
|
||||||
onclick: () =>
|
|
||||||
game.l5r5e.HelpersL5r5e.debounce(
|
|
||||||
"SwitchView-" + this.object.id,
|
|
||||||
() => {
|
|
||||||
this.object.view = this.object.view === "armies" ? "characters" : "armies";
|
|
||||||
this.render(false);
|
|
||||||
},
|
|
||||||
500,
|
|
||||||
true
|
|
||||||
)(),
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add selected tokens
|
|
||||||
buttons.unshift({
|
|
||||||
label: game.i18n.localize("l5r5e.gm.monitor.add_selected_tokens"),
|
|
||||||
class: "add-selected-token",
|
|
||||||
icon: "fas fa-users",
|
|
||||||
onclick: () =>
|
|
||||||
game.l5r5e.HelpersL5r5e.debounce(
|
|
||||||
"AddSelectedToken-" + this.object.id,
|
|
||||||
() => this.#addSelectedTokens(),
|
|
||||||
500,
|
|
||||||
true
|
|
||||||
)(),
|
|
||||||
});
|
|
||||||
|
|
||||||
return buttons;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* The DragDrop instance which handles interactivity resulting from DragTransfer events.
|
||||||
* @param {ApplicationOptions} options
|
* @type {DragDrop}
|
||||||
*/
|
*/
|
||||||
constructor(options = {}) {
|
#dragDrop;
|
||||||
super(options);
|
|
||||||
this._initialize();
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.#initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @override ApplicationV2 */
|
||||||
* Refresh data (used from socket)
|
async _preClose(options) {
|
||||||
*/
|
await super._preClose(options);
|
||||||
async refresh() {
|
options.animate = false;
|
||||||
if (!game.user.isGM) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._initialize();
|
|
||||||
this.render(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
for (const hook of this.#hooks) {
|
||||||
* Initialize the values
|
Hooks.off(hook.hook, hook.fn);
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_initialize() {
|
|
||||||
let actors;
|
|
||||||
const uuidList = game.settings.get(CONFIG.l5r5e.namespace, "gm-monitor-actors");
|
|
||||||
if (uuidList.length > 0) {
|
|
||||||
// Get actors from stored uuids
|
|
||||||
actors = uuidList
|
|
||||||
.map(uuid => {
|
|
||||||
const doc = fromUuidSync(uuid);
|
|
||||||
if (doc instanceof TokenDocument) {
|
|
||||||
return doc.actor;
|
|
||||||
}
|
|
||||||
return doc;
|
|
||||||
})
|
|
||||||
.filter(a => !!a); // skip null
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// If empty add pc with owner
|
|
||||||
actors = game.actors.filter((actor) => actor.type === "character" && actor.hasPlayerOwnerActive);
|
|
||||||
this._saveActorsIds();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort by name asc
|
|
||||||
actors.sort((a, b) => {
|
|
||||||
return a.name.localeCompare(b.name);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.object.actors = actors;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add selected token on monitor if not already present
|
|
||||||
*/
|
|
||||||
#addSelectedTokens() {
|
|
||||||
if (canvas.tokens.controlled.length > 0) {
|
|
||||||
const actors2Add = canvas.tokens.controlled
|
|
||||||
.map(t => t.actor)
|
|
||||||
.filter(t => !!t && !this.object.actors.find((a) => a.uuid === t.uuid));
|
|
||||||
|
|
||||||
if (actors2Add.length < 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.object.actors = [
|
|
||||||
...this.object.actors,
|
|
||||||
...actors2Add
|
|
||||||
];
|
|
||||||
this._saveActorsIds().then(() => this.render(false));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @override ApplicationV2 */
|
||||||
* Prevent non GM to render this windows
|
async _onRender(context, options) {
|
||||||
* @override
|
await super._onRender(context, options);
|
||||||
*/
|
|
||||||
render(force = false, options = {}) {
|
|
||||||
if (!game.user.isGM) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return super.render(force, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// Todo: Move this to common l5r5e application v2
|
||||||
* Construct and return the data object used to render the HTML template for this form application.
|
game.l5r5e.HelpersL5r5e.commonListeners($(this.element));
|
||||||
* @param options
|
|
||||||
* @return {Object}
|
|
||||||
* @override
|
|
||||||
*/
|
|
||||||
async getData(options = null) {
|
|
||||||
return {
|
|
||||||
...(await super.getData(options)),
|
|
||||||
data: {
|
|
||||||
...this.object,
|
|
||||||
actors: this.object.actors.filter((a) => (this.object.view === "armies" ? a.isArmy : !a.isArmy)),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
this.#dragDrop = new DragDrop({
|
||||||
* Listen to html elements
|
dragSelector: null,
|
||||||
* @param {jQuery} html HTML content of the sheet.
|
dropSelector: null,
|
||||||
* @override
|
callbacks: {
|
||||||
*/
|
drop: this.#onDrop.bind(this)
|
||||||
activateListeners(html) {
|
}
|
||||||
super.activateListeners(html);
|
}).bind(this.element);
|
||||||
|
|
||||||
if (!game.user.isGM) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Commons
|
|
||||||
game.l5r5e.HelpersL5r5e.commonListeners(html);
|
|
||||||
|
|
||||||
// Delete
|
|
||||||
html.find(`.actor-remove-control`).on("click", this._removeActor.bind(this));
|
|
||||||
|
|
||||||
// Add/Subtract
|
|
||||||
html.find(`.actor-modify-control`).on("mousedown", this._modifyActor.bind(this));
|
|
||||||
|
|
||||||
// Tooltips
|
// Tooltips
|
||||||
game.l5r5e.HelpersL5r5e.popupManager(html.find(".actor-infos-control"), async (event) => {
|
game.l5r5e.HelpersL5r5e.popupManager($(this.element).find(".actor-infos-control"), async (event) => {
|
||||||
const type = $(event.currentTarget).data("type");
|
const type = $(event.currentTarget).data("type");
|
||||||
if (!type) {
|
if (!type) {
|
||||||
return;
|
return;
|
||||||
@@ -208,29 +149,71 @@ export class GmMonitor extends FormApplication {
|
|||||||
if (!uuid) {
|
if (!uuid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const actor = this.object.actors.find((a) => a.uuid === uuid);
|
const actor = this.context.actors.find((actor) => actor.uuid === uuid);
|
||||||
if (!actor) {
|
if (!actor) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "armors":
|
case "armors":
|
||||||
return this._getTooltipArmors(actor);
|
return this.#getTooltipArmors(actor);
|
||||||
case "weapons":
|
case "weapons":
|
||||||
return this._getTooltipWeapons(actor);
|
return this.#getTooltipWeapons(actor);
|
||||||
case "global":
|
case "global":
|
||||||
return actor.isArmy ? this._getTooltipArmiesGlobal(actor) : this._getTooltipGlobal(actor);
|
return actor.isArmy ? this.#getTooltipArmiesGlobal(actor) : this.#getTooltipGlobal(actor);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @override ApplicationV2 */
|
||||||
|
async _prepareContext() {
|
||||||
|
return {
|
||||||
|
tabs: this.getTabs(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} partId The part being rendered
|
||||||
|
* @param {ApplicationRenderContext} context Shared context provided by _prepareContext
|
||||||
|
* @returns {Promise<ApplicationRenderContext>} Context data for a specific part
|
||||||
|
*
|
||||||
|
* @override HandlebarsApplicationMixin
|
||||||
|
*/
|
||||||
|
async _preparePartContext(partId, context) {
|
||||||
|
switch (partId) {
|
||||||
|
case "character":
|
||||||
|
context.characters = this.context.actors.filter((actor) => !actor.isArmy);
|
||||||
|
break;
|
||||||
|
case "army":
|
||||||
|
context.armies = this.context.actors.filter((actor) => actor.isArmy);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare an array of form header tabs.
|
||||||
|
* @returns {Record<string, Partial<ApplicationTab>>}
|
||||||
|
*/
|
||||||
|
getTabs() {
|
||||||
|
const tabs = {
|
||||||
|
character: { id: "character", group: "view", icon: "fa-solid fa-tag", label: "REGION.SECTIONS.identity" },
|
||||||
|
army: { id: "army", group: "view", icon: "fa-solid fa-shapes", label: "REGION.SECTIONS.shapes" },
|
||||||
|
}
|
||||||
|
for (const v of Object.values(tabs)) {
|
||||||
|
v.active = this.tabGroups[v.group] === v.id;
|
||||||
|
v.cssClass = v.active ? "active" : "";
|
||||||
|
}
|
||||||
|
return tabs;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle dropped data on the Actor sheet
|
* Handle dropped data on the Actor sheet
|
||||||
* @param {DragEvent} event
|
* @param {DragEvent} event The originating DragEvent
|
||||||
*/
|
*/
|
||||||
async _onDrop(event) {
|
async #onDrop(event) {
|
||||||
// *** Everything below here is only needed if the sheet is editable ***
|
|
||||||
if (!this.isEditable) {
|
if (!this.options.window.editable) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,7 +223,7 @@ export class GmMonitor extends FormApplication {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const data = JSON.parse(json);
|
const data = JSON.parse(json);
|
||||||
if (!data || data.type !== "Actor" || !data.uuid || !!this.object.actors.find((a) => a.uuid === data.uuid)) {
|
if (!data || data.type !== "Actor" || !data.uuid || !!this.context.actors.find((a) => a.uuid === data.uuid)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,159 +233,383 @@ export class GmMonitor extends FormApplication {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Switch view to current character type
|
// Switch view to current character type
|
||||||
this.object.view = actor.isArmy ? "armies" : "characters";
|
if (actor.isArmy) {
|
||||||
|
this.changeTab("army", "view");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.changeTab("character", "view");
|
||||||
|
}
|
||||||
|
|
||||||
this.object.actors.push(actor);
|
this.context.actors.push(actor);
|
||||||
|
|
||||||
return this._saveActorsIds();
|
return this.saveActorsIds();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** required for updating via our socket implementation game.l5r5e.HelpersL5r5e.refreshLocalAndSocket("l5r5e-gm-monitor")*/
|
||||||
|
async refresh() {
|
||||||
|
this.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save the actors ids in settings
|
* Save the actors ids in setting
|
||||||
* @return {Promise<*>}
|
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
async _saveActorsIds() {
|
async saveActorsIds() {
|
||||||
return game.settings.set(
|
return game.settings.set(
|
||||||
CONFIG.l5r5e.namespace,
|
CONFIG.l5r5e.namespace,
|
||||||
"gm-monitor-actors",
|
"gm-monitor-actors",
|
||||||
this.object.actors.map((a) => a.uuid)
|
this.context.actors.map((a) => a.uuid)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
#initialize() {
|
||||||
* Remove the link to a property for the current item
|
let actors;
|
||||||
* @param {Event} event
|
const uuidList = game.settings.get(CONFIG.l5r5e.namespace, "gm-monitor-actors");
|
||||||
* @return {Promise<void>}
|
if (uuidList.length > 0) {
|
||||||
* @private
|
// Get actors from stored uuids
|
||||||
*/
|
actors = uuidList
|
||||||
async _removeActor(event) {
|
.map(uuid => {
|
||||||
event.preventDefault();
|
const doc = fromUuidSync(uuid);
|
||||||
event.stopPropagation();
|
if (doc instanceof TokenDocument) {
|
||||||
|
return doc.actor;
|
||||||
|
}
|
||||||
|
return doc;
|
||||||
|
})
|
||||||
|
.filter(actor => !!actor); // skip null
|
||||||
|
|
||||||
const uuid = $(event.currentTarget).data("actor-uuid");
|
} else {
|
||||||
if (!uuid) {
|
// If empty add pc with owner
|
||||||
return;
|
actors = game.actors.filter((actor) => actor.type === "character" && actor.hasPlayerOwnerActive);
|
||||||
|
this.saveActorsIds();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.object.actors = this.object.actors.filter((a) => a.uuid !== uuid);
|
// Sort by name asc
|
||||||
|
actors.sort((a, b) => {
|
||||||
|
return a.name.localeCompare(b.name);
|
||||||
|
});
|
||||||
|
|
||||||
return this._saveActorsIds();
|
this.context.actors = actors;
|
||||||
|
|
||||||
|
this.#hooks.push({
|
||||||
|
hook: "updateActor",
|
||||||
|
fn: Hooks.on("updateActor", (actor) => this.#onUpdateActor(actor))
|
||||||
|
});
|
||||||
|
this.#hooks.push({
|
||||||
|
hook: "updateSetting",
|
||||||
|
fn: Hooks.on("updateSetting", (actor) => this.#onUpdateSetting(actor))
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add or subtract fatigue/strife/void/casualties/panic
|
* Switch between the available views in sequence
|
||||||
* @param event
|
|
||||||
* @return {Promise<void>}
|
|
||||||
* @private
|
|
||||||
*/
|
*/
|
||||||
async _modifyActor(event) {
|
static #rotateViewTab() {
|
||||||
event.preventDefault();
|
const tabArray = Object.values(this.getTabs());
|
||||||
event.stopPropagation();
|
const activeTabIndex = tabArray.findIndex((tab) => tab.active);
|
||||||
|
const nextTabIndex = activeTabIndex + 1 < tabArray.length ? activeTabIndex + 1 : 0;
|
||||||
|
this.changeTab(tabArray[nextTabIndex].id, tabArray[nextTabIndex].group)
|
||||||
|
}
|
||||||
|
|
||||||
const type = $(event.currentTarget).data("type");
|
/**
|
||||||
if (!type) {
|
* Add selected token on monitor if not already present
|
||||||
console.warn("L5R5E | GMM | type not set", type);
|
*/
|
||||||
return;
|
static #addSelectedTokens() {
|
||||||
|
if (canvas.tokens.controlled.length > 0) {
|
||||||
|
const actors2Add = canvas.tokens.controlled
|
||||||
|
.map(t => t.actor)
|
||||||
|
.filter(t => !!t && !this.context.actors.find((a) => a.uuid === t.uuid));
|
||||||
|
|
||||||
|
if (actors2Add.length < 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.context.actors = [
|
||||||
|
...this.context.actors,
|
||||||
|
...actors2Add
|
||||||
|
];
|
||||||
|
this.saveActorsIds();
|
||||||
}
|
}
|
||||||
const uuid = $(event.currentTarget).data("actor-uuid");
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update baseValue based on the type of event
|
||||||
|
* @param {Int} baseValue The Base value we can to modify
|
||||||
|
* @param {Int} whichButton The type of click made
|
||||||
|
*/
|
||||||
|
static #newValue(baseValue, whichButton) {
|
||||||
|
switch (whichButton) {
|
||||||
|
case 0: //Left click
|
||||||
|
return Math.max(0, baseValue + 1);
|
||||||
|
case 1: //Middle click
|
||||||
|
return 0;
|
||||||
|
case 2: //Right click
|
||||||
|
return Math.max(0, baseValue - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {HTMLElement} target Html target to get actor information from
|
||||||
|
*/
|
||||||
|
static async #getActorValidated(target) {
|
||||||
|
const uuid = $(target).data("actor-uuid");
|
||||||
if (!uuid) {
|
if (!uuid) {
|
||||||
console.warn("L5R5E | GMM | actor uuid not set", type);
|
console.warn("L5R5E | GMM | actor uuid not set", type);
|
||||||
return;
|
return {isValid: false, actor: null};
|
||||||
}
|
}
|
||||||
const actor = fromUuidSync(uuid);
|
const actor = await fromUuid(uuid);
|
||||||
if (!actor) {
|
if (!actor) {
|
||||||
console.warn("L5R5E | GMM | Actor not found", type);
|
console.warn("L5R5E | GMM | Actor not found", type);
|
||||||
|
return {isValid: false, actor: null};
|
||||||
|
}
|
||||||
|
return {isValid:true, actor: actor};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {PointerEvent} event The originating click event
|
||||||
|
* @param {HTMLElement} target The capturing HTML element which defined a [data-action]
|
||||||
|
*/
|
||||||
|
static async #modifyCasualties(event, target) {
|
||||||
|
const {isValid, actor} = await GmMonitor.#getActorValidated(target);
|
||||||
|
if (!isValid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mouse bt : middle = 0, left +1, right -1
|
const casualties_strength = actor.system.battle_readiness.casualties_strength.value;
|
||||||
const add = event.which === 2 ? -999 : event.which === 1 ? 1 : -1;
|
return actor.update({
|
||||||
|
system: {
|
||||||
|
battle_readiness: {
|
||||||
|
casualties_strength: {
|
||||||
|
value: GmMonitor.#newValue(casualties_strength, event.button),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Stance
|
/**
|
||||||
let stanceIdx = CONFIG.l5r5e.stances.findIndex((s) => s === actor.system.stance) + (event.which === 1 ? 1 : -1);
|
* @param {PointerEvent} event The originating click event
|
||||||
|
* @param {HTMLElement} target The capturing HTML element which defined a [data-action]
|
||||||
|
*/
|
||||||
|
static async #modifyPanic(event, target) {
|
||||||
|
const {isValid, actor} = await GmMonitor.#getActorValidated(target);
|
||||||
|
if (!isValid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const panic_discipline = actor.system.battle_readiness.panic_discipline.value;
|
||||||
|
return actor.update({
|
||||||
|
system: {
|
||||||
|
battle_readiness: {
|
||||||
|
panic_discipline: {
|
||||||
|
value: GmMonitor.#newValue(panic_discipline, event.button),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {PointerEvent} event The originating click event
|
||||||
|
* @param {HTMLElement} target The capturing HTML element which defined a [data-action]
|
||||||
|
*/
|
||||||
|
static async #togglePrepared(event, target) {
|
||||||
|
const {isValid, actor} = await GmMonitor.#getActorValidated(target);
|
||||||
|
if (!isValid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return actor.update({
|
||||||
|
system: {
|
||||||
|
prepared: !actor.system.prepared
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {PointerEvent} event The originating click event
|
||||||
|
* @param {HTMLElement} target The capturing HTML element which defined a [data-action]
|
||||||
|
*/
|
||||||
|
static async #changeStance(event, target) {
|
||||||
|
const {isValid, actor} = await GmMonitor.#getActorValidated(target);
|
||||||
|
if (!isValid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let stanceIdx = CONFIG.l5r5e.stances.findIndex((stance) => stance === actor.system.stance) + (event.button === 0 ? 1 : -1);
|
||||||
if (stanceIdx < 0) {
|
if (stanceIdx < 0) {
|
||||||
stanceIdx = CONFIG.l5r5e.stances.length - 1;
|
stanceIdx = CONFIG.l5r5e.stances.length - 1;
|
||||||
} else if (stanceIdx > CONFIG.l5r5e.stances.length - 1) {
|
} else if (stanceIdx > CONFIG.l5r5e.stances.length - 1) {
|
||||||
stanceIdx = 0;
|
stanceIdx = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateData = {};
|
return actor.update({
|
||||||
switch (type) {
|
system: {
|
||||||
// *** Characters ***
|
stance: CONFIG.l5r5e.stances[stanceIdx]
|
||||||
case "fatigue":
|
},
|
||||||
updateData["system.fatigue.value"] = Math.max(0, actor.system.fatigue.value + add);
|
});
|
||||||
break;
|
|
||||||
|
|
||||||
case "strife":
|
|
||||||
updateData["system.strife.value"] = Math.max(0, actor.system.strife.value + add);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "void_points":
|
|
||||||
updateData["system.void_points.value"] = Math.min(
|
|
||||||
actor.system.void_points.max,
|
|
||||||
Math.max(0, actor.system.void_points.value + add)
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "stance":
|
|
||||||
updateData["system.stance"] = CONFIG.l5r5e.stances[stanceIdx];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "prepared":
|
|
||||||
updateData["system.prepared"] = !actor.system.prepared;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// *** Armies ***
|
|
||||||
case "casualties":
|
|
||||||
updateData["system.battle_readiness.casualties_strength.value"] = Math.max(
|
|
||||||
0,
|
|
||||||
actor.system.battle_readiness.casualties_strength.value + add
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "panic":
|
|
||||||
updateData["system.battle_readiness.panic_discipline.value"] = Math.max(
|
|
||||||
0,
|
|
||||||
actor.system.battle_readiness.panic_discipline.value + add
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
console.warn("L5R5E | GMM | Unsupported type", type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!foundry.utils.isEmpty(updateData)) {
|
|
||||||
await actor.update(updateData);
|
|
||||||
this.render(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param {PointerEvent} event The originating click event
|
||||||
|
* @param {HTMLElement} target The capturing HTML element which defined a [data-action]
|
||||||
|
*/
|
||||||
|
static async #modifyFatigue(event, target) {
|
||||||
|
const {isValid, actor} = await GmMonitor.#getActorValidated(target);
|
||||||
|
if (!isValid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fatigue = actor.system.fatigue.value;
|
||||||
|
return actor.update({
|
||||||
|
system: {
|
||||||
|
fatigue: {
|
||||||
|
value: GmMonitor.#newValue(fatigue, event.button)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {PointerEvent} event The originating click event
|
||||||
|
* @param {HTMLElement} target The capturing HTML element which defined a [data-action]
|
||||||
|
*/
|
||||||
|
static async #modifyStrife(event, target) {
|
||||||
|
const {isValid, actor} = await GmMonitor.#getActorValidated(target);
|
||||||
|
if (!isValid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const strife = actor.system.strife.value;
|
||||||
|
return actor.update({
|
||||||
|
system: {
|
||||||
|
strife: {
|
||||||
|
value: GmMonitor.#newValue(strife, event.button),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {PointerEvent} event The originating click event
|
||||||
|
* @param {HTMLElement} target The capturing HTML element which defined a [data-action]
|
||||||
|
*/
|
||||||
|
static async #modifyVoidPoint(event, target) {
|
||||||
|
const {isValid, actor} = await GmMonitor.#getActorValidated(target);
|
||||||
|
if (!isValid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const void_points = actor.system.void_points.value;
|
||||||
|
const void_points_max = actor.system.void_points.max;
|
||||||
|
return actor.update({
|
||||||
|
system: {
|
||||||
|
void_points: {
|
||||||
|
value: Math.min(
|
||||||
|
void_points_max,
|
||||||
|
GmMonitor.#newValue(void_points, event.button)
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {PointerEvent} event The originating click event
|
||||||
|
* @param {HTMLElement} target The capturing HTML element which defined a [data-action]
|
||||||
|
*/
|
||||||
|
static async #removeActor(event, target) {
|
||||||
|
const uuid = $(target).data("actor-uuid");
|
||||||
|
if (!uuid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.context.actors = this.context.actors.filter((actor) => actor.uuid !== uuid);
|
||||||
|
return this.saveActorsIds();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get armors information for this actor
|
||||||
|
* @param {ActorL5r5e} actor
|
||||||
|
* @return {string}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
async #getTooltipArmors(actor) {
|
||||||
|
// Equipped Armors
|
||||||
|
const armors = actor.items
|
||||||
|
.filter((item) => item.type === "armor" && item.system.equipped)
|
||||||
|
.map(
|
||||||
|
(item) =>
|
||||||
|
item.name +
|
||||||
|
` (<i class="fas fa-tint">${item.system.armor.physical}</i>` +
|
||||||
|
` / <i class="fas fa-bolt">${item.system.armor.supernatural}</i>)`
|
||||||
|
);
|
||||||
|
|
||||||
|
// *** Template ***
|
||||||
|
return renderTemplate(`${CONFIG.l5r5e.paths.templates}gm/monitor/tooltips/armors.html`, {
|
||||||
|
armors,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get weapons information for this actor
|
||||||
|
* @param {ActorL5r5e} actor
|
||||||
|
* @return {string}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
async #getTooltipWeapons(actor) {
|
||||||
|
const display = (weapon) => {
|
||||||
|
return (
|
||||||
|
weapon.name +
|
||||||
|
` (<i class="fas fa-arrows-alt-h"> ${weapon.system.range}</i>` +
|
||||||
|
` / <i class="fas fa-tint"> ${weapon.system.damage}</i>` +
|
||||||
|
` / <i class="fas fa-skull"> ${weapon.system.deadliness}</i>)`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Readied Weapons
|
||||||
|
const equippedWeapons = actor.items.filter((item) => item.type === "weapon" && item.system.equipped);
|
||||||
|
|
||||||
|
const readied = equippedWeapons
|
||||||
|
.filter((weapon) => !!weapon.system.readied)
|
||||||
|
.map((weapon) => display(weapon));
|
||||||
|
|
||||||
|
// Equipped Weapons
|
||||||
|
const sheathed = equippedWeapons
|
||||||
|
.filter((weapon) => !weapon.system.readied)
|
||||||
|
.map((weapon) => display(weapon));
|
||||||
|
|
||||||
|
// *** Template ***
|
||||||
|
return renderTemplate(`${CONFIG.l5r5e.paths.templates}gm/monitor/tooltips/weapons.html`, {
|
||||||
|
readied,
|
||||||
|
sheathed,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
* Get tooltips information for this character
|
* Get tooltips information for this character
|
||||||
* @param {ActorL5r5e} actor
|
* @param {ActorL5r5e} actor
|
||||||
* @return {string}
|
* @return {string}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
async _getTooltipGlobal(actor) {
|
async #getTooltipGlobal(actor) {
|
||||||
const actorData = (await actor.sheet?.getData()?.data) || actor;
|
const actorData = (await actor.sheet?.getData()?.data) || actor;
|
||||||
|
|
||||||
// Peculiarities
|
// Peculiarities
|
||||||
const pec = actor.items.filter((e) => e.type === "peculiarity");
|
const Peculiarities = actor.items.filter((e) => e.type === "peculiarity");
|
||||||
const adv = pec
|
const advantages = Peculiarities
|
||||||
.filter((e) => ["distinction", "passion"].includes(e.system.peculiarity_type))
|
.filter((item) => ["distinction", "passion"].includes(item.system.peculiarity_type))
|
||||||
.map((e) => e.name)
|
.map((item) => item.name)
|
||||||
.join(", ");
|
.join(", ");
|
||||||
const dis = pec
|
const disadvantages = Peculiarities
|
||||||
.filter((e) => ["adversity", "anxiety"].includes(e.system.peculiarity_type))
|
.filter((item) => ["adversity", "anxiety"].includes(item.system.peculiarity_type))
|
||||||
.map((e) => e.name)
|
.map((item) => item.name)
|
||||||
.join(", ");
|
.join(", ");
|
||||||
|
|
||||||
// *** Template ***
|
// *** Template ***
|
||||||
return renderTemplate(`${CONFIG.l5r5e.paths.templates}gm/monitor-tooltips/global.html`, {
|
return renderTemplate(`${CONFIG.l5r5e.paths.templates}gm/monitor/tooltips/global.html`, {
|
||||||
actorData: actorData,
|
actorData: actorData,
|
||||||
advantages: adv,
|
advantages: advantages,
|
||||||
disadvantages: dis,
|
disadvantages: disadvantages,
|
||||||
suffix: actorData.system.template === "pow" ? "_pow" : "",
|
suffix: actorData.system.template === "pow" ? "_pow" : "",
|
||||||
actor_type: actor.type,
|
actor_type: actor.type,
|
||||||
});
|
});
|
||||||
@@ -414,68 +621,39 @@ export class GmMonitor extends FormApplication {
|
|||||||
* @return {string}
|
* @return {string}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
async _getTooltipArmiesGlobal(actor) {
|
async #getTooltipArmiesGlobal(actor) {
|
||||||
const actorData = (await actor.sheet?.getData()?.data) || actor;
|
const actorData = (await actor.sheet?.getData()?.data) || actor;
|
||||||
|
|
||||||
// *** Template ***
|
// *** Template ***
|
||||||
return renderTemplate(`${CONFIG.l5r5e.paths.templates}gm/monitor-tooltips/global-armies.html`, {
|
return renderTemplate(`${CONFIG.l5r5e.paths.templates}gm/monitor/tooltips/global-armies.html`, {
|
||||||
actorData: actorData,
|
actorData: actorData,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get weapons information for this actor
|
* @param {ActorL5r5e} actor The actor that is being updated
|
||||||
* @param {ActorL5r5e} actor
|
|
||||||
* @return {string}
|
|
||||||
* @private
|
|
||||||
*/
|
*/
|
||||||
async _getTooltipWeapons(actor) {
|
#onUpdateActor(actor) {
|
||||||
const display = (e) => {
|
if (this.context.actors.includes(actor)) {
|
||||||
return (
|
this.render(false);
|
||||||
e.name +
|
}
|
||||||
` (<i class="fas fa-arrows-alt-h"> ${e.system.range}</i>` +
|
|
||||||
` / <i class="fas fa-tint"> ${e.system.damage}</i>` +
|
|
||||||
` / <i class="fas fa-skull"> ${e.system.deadliness}</i>)`
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Readied Weapons
|
|
||||||
const readied = actor.items
|
|
||||||
.filter((e) => e.type === "weapon" && e.system.equipped && !!e.system.readied)
|
|
||||||
.map((e) => display(e));
|
|
||||||
|
|
||||||
// Equipped Weapons
|
|
||||||
const sheathed = actor.items
|
|
||||||
.filter((e) => e.type === "weapon" && e.system.equipped && !e.system.readied)
|
|
||||||
.map((e) => display(e));
|
|
||||||
|
|
||||||
// *** Template ***
|
|
||||||
return renderTemplate(`${CONFIG.l5r5e.paths.templates}gm/monitor-tooltips/weapons.html`, {
|
|
||||||
readied,
|
|
||||||
sheathed,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get armors information for this actor
|
* @param {Setting} setting The setting that is being updated
|
||||||
* @param {ActorL5r5e} actor
|
|
||||||
* @return {string}
|
|
||||||
* @private
|
|
||||||
*/
|
*/
|
||||||
async _getTooltipArmors(actor) {
|
#onUpdateSetting(setting) {
|
||||||
// Equipped Armors
|
switch (setting.key) {
|
||||||
const armors = actor.items
|
case "l5r5e.gm-monitor-actors":
|
||||||
.filter((e) => e.type === "armor" && e.system.equipped)
|
this.render(false);
|
||||||
.map(
|
break;
|
||||||
(e) =>
|
case "l5r5e.initiative-prepared-character":
|
||||||
e.name +
|
case "l5r5e.initiative-prepared-adversary":
|
||||||
` (<i class="fas fa-tint">${e.system.armor.physical}</i>` +
|
case "l5r5e.initiative-prepared-minion":
|
||||||
` / <i class="fas fa-bolt">${e.system.armor.supernatural}</i>)`
|
this.render(false);
|
||||||
);
|
break;
|
||||||
|
default:
|
||||||
// *** Template ***
|
return;
|
||||||
return renderTemplate(`${CONFIG.l5r5e.paths.templates}gm/monitor-tooltips/armors.html`, {
|
}
|
||||||
armors,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +1,96 @@
|
|||||||
/**
|
const HandlebarsApplicationMixin = foundry.applications.api.HandlebarsApplicationMixin;
|
||||||
* L5R GM Toolbox dialog
|
const ApplicationV2 = foundry.applications.api.ApplicationV2;
|
||||||
* @extends {FormApplication}
|
export class GmToolbox extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||||
*/
|
/** @override ApplicationV2 */
|
||||||
export class GmToolbox extends FormApplication {
|
static get DEFAULT_OPTIONS() { return {
|
||||||
/**
|
id: "l5r5e-gm-toolbox",
|
||||||
* Settings
|
window: {
|
||||||
*/
|
contentClasses: ["l5r5e", "gm-toolbox"],
|
||||||
object = {};
|
title: "l5r5e.gm.toolbox.title",
|
||||||
|
minimizable: true,
|
||||||
|
},
|
||||||
|
position: {
|
||||||
|
width: "auto",
|
||||||
|
height: "auto"
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
open_gm_monitor: GmToolbox.#openGmMonitor,
|
||||||
|
toggle_hide_difficulty: GmToolbox.#onToggleHideDifficulty,
|
||||||
|
change_difficulty: {
|
||||||
|
buttons: [0, 1, 2],
|
||||||
|
handler: GmToolbox.#onChangeDifficulty
|
||||||
|
},
|
||||||
|
reset_void: {
|
||||||
|
buttons: [0, 1, 2, 3, 4], // all the buttons (left, middle, right, extra 1, extra 2)
|
||||||
|
handler: GmToolbox.#onResetVoid
|
||||||
|
},
|
||||||
|
sleep: {
|
||||||
|
buttons: [0, 1, 2, 3, 4],
|
||||||
|
handler: GmToolbox.#onSleep
|
||||||
|
},
|
||||||
|
scene_end: {
|
||||||
|
buttons: [0, 1, 2, 3, 4],
|
||||||
|
handler: GmToolbox.#onSceneEnd
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
|
||||||
|
/** @override HandlebarsApplicationMixin */
|
||||||
|
static PARTS = {
|
||||||
|
main: {
|
||||||
|
id: "gm-tool-content",
|
||||||
|
template: "systems/l5r5e/templates/" + "gm/gm-toolbox.html"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assign the default options
|
* hooks we act upon, saved since we need to remove them when this window is not open
|
||||||
* @override
|
|
||||||
*/
|
*/
|
||||||
static get defaultOptions() {
|
#hooks = [];
|
||||||
const x = $(window).width();
|
|
||||||
const y = $(window).height();
|
constructor() {
|
||||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
super();
|
||||||
id: "l5r5e-gm-toolbox",
|
this.#hooks.push({
|
||||||
classes: ["l5r5e", "gm-toolbox"],
|
hook: "updateSetting",
|
||||||
template: CONFIG.l5r5e.paths.templates + "gm/gm-toolbox.html",
|
fn: Hooks.on("updateSetting", (setting) => this.#onUpdateSetting(setting))
|
||||||
title: game.i18n.localize("l5r5e.gm.toolbox.title"),
|
|
||||||
left: x - 630,
|
|
||||||
top: y - 98,
|
|
||||||
closeOnSubmit: false,
|
|
||||||
submitOnClose: false,
|
|
||||||
submitOnChange: true,
|
|
||||||
minimizable: false,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @override ApplicationV2*/
|
||||||
|
async _prepareContext() {
|
||||||
|
return {
|
||||||
|
difficulty: game.settings.get(CONFIG.l5r5e.namespace, "initiative-difficulty-value"),
|
||||||
|
difficultyHidden: game.settings.get(CONFIG.l5r5e.namespace, "initiative-difficulty-hidden"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* The ApplicationV2 always adds the close button so just remove it when redering the frame
|
||||||
* @param {ApplicationOptions} options
|
* @override ApplicationV2
|
||||||
*/
|
*/
|
||||||
constructor(options = {}) {
|
async _renderFrame(options) {
|
||||||
super(options);
|
const frame = await super._renderFrame(options);
|
||||||
this._initialize();
|
$(frame).find('button[data-action="close"]').remove();
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ApplicationV2 always adds the close button so just remove it when redering the frame
|
||||||
|
* @override ApplicationV2
|
||||||
|
*/
|
||||||
|
_onFirstRender(context, options) {
|
||||||
|
const x = $(window).width();
|
||||||
|
const y = $(window).height();
|
||||||
|
options.position.top = y - 100;
|
||||||
|
options.position.left = x - 630;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The GM Toolbox should not be removed when toggling the main menu with the esc key etc.
|
||||||
|
* @override ApplicationV2
|
||||||
|
*/
|
||||||
|
async close(options) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -45,210 +100,155 @@ export class GmToolbox extends FormApplication {
|
|||||||
if (!game.user.isGM) {
|
if (!game.user.isGM) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._initialize();
|
|
||||||
this.render(false);
|
this.render(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static #openGmMonitor() {
|
||||||
* Initialize the values
|
const app = foundry.applications.instances.get("l5r5e-gm-monitor")
|
||||||
* @private
|
if (app) {
|
||||||
*/
|
app.close();
|
||||||
_initialize() {
|
|
||||||
this.object = {
|
|
||||||
difficulty: game.settings.get(CONFIG.l5r5e.namespace, "initiative-difficulty-value"),
|
|
||||||
difficultyHidden: game.settings.get(CONFIG.l5r5e.namespace, "initiative-difficulty-hidden"),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Do not close this dialog
|
|
||||||
* @override
|
|
||||||
*/
|
|
||||||
async close(options = {}) {
|
|
||||||
// TODO better implementation needed : see KeyboardManager._onEscape(event, up, modifiers)
|
|
||||||
// This windows is always open, so esc key is stuck at step 2 : Object.keys(ui.windows).length > 0
|
|
||||||
// Case 3 (GM) - release controlled objects
|
|
||||||
if (canvas?.ready && game.user.isGM && Object.keys(canvas.activeLayer.controlled).length) {
|
|
||||||
canvas.activeLayer.releaseAll();
|
|
||||||
} else {
|
} else {
|
||||||
// Case 4 - toggle the main menu
|
new game.l5r5e.GmMonitor().render(true);
|
||||||
ui.menu.toggle();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prevent non GM to render this windows
|
* @param {PointerEvent} event The originating click event
|
||||||
* @override
|
|
||||||
*/
|
*/
|
||||||
render(force = false, options = {}) {
|
static #onChangeDifficulty(event) {
|
||||||
if (!game.user.isGM) {
|
let difficulty = game.settings.get(CONFIG.l5r5e.namespace, "initiative-difficulty-value");
|
||||||
|
switch (event.button) {
|
||||||
|
case 0: // left click
|
||||||
|
difficulty = Math.min(9, difficulty + 1);
|
||||||
|
break;
|
||||||
|
case 1: // middle click
|
||||||
|
difficulty = 2;
|
||||||
|
break;
|
||||||
|
case 2: // right click
|
||||||
|
difficulty = Math.max(0, difficulty - 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
game.settings.set(CONFIG.l5r5e.namespace, "initiative-difficulty-value", difficulty);
|
||||||
|
}
|
||||||
|
|
||||||
|
static #onToggleHideDifficulty() {
|
||||||
|
const hiddenSetting = game.settings.get(CONFIG.l5r5e.namespace, "initiative-difficulty-hidden")
|
||||||
|
game.settings.set(CONFIG.l5r5e.namespace, "initiative-difficulty-hidden", !hiddenSetting);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Boolean} allActors
|
||||||
|
* @param {ActorL5r5e} actor
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
static #updatableCharacter(allActors, actor) {
|
||||||
|
if (!actor.isCharacterType) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
this.position.width = "auto";
|
|
||||||
this.position.height = "auto";
|
|
||||||
return super.render(force, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
if (allActors) {
|
||||||
* Remove the close button
|
return true;
|
||||||
* @override
|
|
||||||
*/
|
|
||||||
_getHeaderButtons() {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct and return the data object used to render the HTML template for this form application.
|
|
||||||
* @param options
|
|
||||||
* @return {Object}
|
|
||||||
* @override
|
|
||||||
*/
|
|
||||||
async getData(options = null) {
|
|
||||||
return {
|
|
||||||
...(await super.getData(options)),
|
|
||||||
data: this.object,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Listen to html elements
|
|
||||||
* @param {jQuery} html HTML content of the sheet.
|
|
||||||
* @override
|
|
||||||
*/
|
|
||||||
activateListeners(html) {
|
|
||||||
super.activateListeners(html);
|
|
||||||
|
|
||||||
if (!game.user.isGM) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
return actor.isCharacter && actor.hasPlayerOwnerActive
|
||||||
// Modify difficulty hidden
|
|
||||||
html.find(`.difficulty_hidden`).on("click", (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
this.object.difficultyHidden = !this.object.difficultyHidden;
|
|
||||||
game.settings
|
|
||||||
.set(CONFIG.l5r5e.namespace, "initiative-difficulty-hidden", this.object.difficultyHidden)
|
|
||||||
.then(() => this.submit());
|
|
||||||
});
|
|
||||||
|
|
||||||
// Modify difficulty (TN)
|
|
||||||
html.find(`.difficulty`).on("mousedown", (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
switch (event.which) {
|
|
||||||
case 1:
|
|
||||||
// left clic - add 1
|
|
||||||
this.object.difficulty = Math.min(9, this.object.difficulty + 1);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
// middle clic - reset to 2
|
|
||||||
this.object.difficulty = 2;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
// right clic - minus 1
|
|
||||||
this.object.difficulty = Math.max(0, this.object.difficulty - 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
game.settings.set(CONFIG.l5r5e.namespace, "initiative-difficulty-value", this.object.difficulty).then(() => this.submit());
|
|
||||||
});
|
|
||||||
|
|
||||||
// Scene End, Sleep, Void Pts
|
|
||||||
html.find(`.gm_actor_updates`).on("mousedown", this._updatesActors.bind(this));
|
|
||||||
|
|
||||||
// GM Monitor
|
|
||||||
html.find(`.gm_monitor`).on("click", (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
|
|
||||||
const app = Object.values(ui.windows).find((e) => e.id === "l5r5e-gm-monitor");
|
|
||||||
if (app) {
|
|
||||||
app.close();
|
|
||||||
} else {
|
|
||||||
new game.l5r5e.GmMonitor().render(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called upon form submission after form data is validated
|
*
|
||||||
* @param event The initial triggering submission event
|
* @param {Boolean} allActors
|
||||||
* @param formData The object of validated form data with which to update the object
|
* @param {String} type
|
||||||
* @returns A Promise which resolves once the update operation has completed
|
|
||||||
* @override
|
|
||||||
*/
|
*/
|
||||||
async _updateObject(event, formData) {
|
static #uiNotification(allActors, type) {
|
||||||
this.render(false);
|
ui.notifications.info(
|
||||||
|
` <i class="fas fa-user${allActors ? "s" : ""}"></i> ` + game.i18n.localize(`l5r5e.gm.toolbox.${type}_info`)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update all actors
|
* @param {PointerEvent} event The originating click event
|
||||||
* @param {Event} event
|
|
||||||
* @private
|
|
||||||
*/
|
*/
|
||||||
async _updatesActors(event) {
|
static async #onResetVoid(event) {
|
||||||
if (!game.user.isGM) {
|
const allActors = event.button !== 0;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Left clic: assigned characters only, others: all actors
|
|
||||||
const isAll = event.which !== 1;
|
|
||||||
const type = $(event.currentTarget).data("type");
|
|
||||||
|
|
||||||
for await (const actor of game.actors.contents) {
|
for await (const actor of game.actors.contents) {
|
||||||
// Only characters types
|
if (!GmToolbox.#updatableCharacter(allActors, actor)) {
|
||||||
if (!actor.isCharacterType) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manage left/right button
|
|
||||||
if (!isAll && (!actor.isCharacter || !actor.hasPlayerOwnerActive)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case "sleep":
|
|
||||||
// Remove 'water x2' fatigue points
|
|
||||||
actor.system.fatigue.value = Math.max(
|
|
||||||
0,
|
|
||||||
actor.system.fatigue.value - Math.ceil(actor.system.rings.water * 2)
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "scene_end":
|
|
||||||
// If more than half the value => roundup half conflit & fatigue
|
|
||||||
actor.system.fatigue.value = Math.min(
|
|
||||||
actor.system.fatigue.value,
|
|
||||||
Math.ceil(actor.system.fatigue.max / 2)
|
|
||||||
);
|
|
||||||
actor.system.strife.value = Math.min(
|
|
||||||
actor.system.strife.value,
|
|
||||||
Math.ceil(actor.system.strife.max / 2)
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "reset_void":
|
|
||||||
actor.system.void_points.value = Math.ceil(actor.system.void_points.max / 2);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
await actor.update({
|
await actor.update({
|
||||||
system: {
|
system: {
|
||||||
fatigue: {
|
|
||||||
value: actor.system.fatigue.value,
|
|
||||||
},
|
|
||||||
strife: {
|
|
||||||
value: actor.system.strife.value,
|
|
||||||
},
|
|
||||||
void_points: {
|
void_points: {
|
||||||
value: actor.system.void_points.value,
|
value: Math.ceil(actor.system.void_points.max / 2),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.notifications.info(
|
GmToolbox.#uiNotification(allActors, "reset_void");
|
||||||
` <i class="fas fa-user${isAll ? "s" : ""}"></i> ` + game.i18n.localize(`l5r5e.gm.toolbox.${type}_info`)
|
}
|
||||||
);
|
|
||||||
|
/**
|
||||||
|
* @param {PointerEvent} event The originating click event
|
||||||
|
*/
|
||||||
|
static async #onSleep(event) {
|
||||||
|
const allActors = event.button !== 0;
|
||||||
|
for await (const actor of game.actors.contents) {
|
||||||
|
if (!GmToolbox.#updatableCharacter(allActors, actor)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
await actor.update({
|
||||||
|
system: {
|
||||||
|
fatigue: {
|
||||||
|
value: Math.max(0,
|
||||||
|
actor.system.fatigue.value - Math.ceil(actor.system.rings.water * 2)
|
||||||
|
),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
GmToolbox.#uiNotification(allActors, "sleep");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {PointerEvent} event The originating click event
|
||||||
|
*/
|
||||||
|
static async #onSceneEnd(event) {
|
||||||
|
const allActors = event.button !== 0;
|
||||||
|
for await (const actor of game.actors.contents) {
|
||||||
|
if (!GmToolbox.#updatableCharacter(allActors, actor)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
await actor.update({
|
||||||
|
system: {
|
||||||
|
fatigue: {
|
||||||
|
value: Math.min(
|
||||||
|
actor.system.fatigue.value,
|
||||||
|
Math.ceil(actor.system.fatigue.max / 2)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
strife: {
|
||||||
|
value: Math.min(
|
||||||
|
actor.system.strife.value,
|
||||||
|
Math.ceil(actor.system.strife.max / 2)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
GmToolbox.#uiNotification(allActors, "scene_end");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Setting} setting The setting that is being updated
|
||||||
|
*/
|
||||||
|
async #onUpdateSetting(setting) {
|
||||||
|
switch (setting.key) {
|
||||||
|
case "l5r5e.initiative-difficulty-value":
|
||||||
|
case "l5r5e.initiative-difficulty-hidden":
|
||||||
|
this.render(false);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -401,12 +401,22 @@ export class HelpersL5r5e {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static getApplication(appId) {
|
||||||
|
const app = Object.values(ui.windows).find((e) => e.id === appId);
|
||||||
|
if(app)
|
||||||
|
return app;
|
||||||
|
|
||||||
|
const appV2 = foundry.applications.instances.get(appId)
|
||||||
|
if(appV2)
|
||||||
|
return appV2;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify Applications using Difficulty settings that the values was changed
|
* Notify Applications using Difficulty settings that the values was changed
|
||||||
*/
|
*/
|
||||||
static notifyDifficultyChange() {
|
static notifyDifficultyChange() {
|
||||||
["l5r5e-dice-picker-dialog", "l5r5e-gm-toolbox"].forEach((appId) => {
|
["l5r5e-dice-picker-dialog"].forEach((appId) => {
|
||||||
const app = Object.values(ui.windows).find((e) => e.id === appId);
|
const app = this.getApplication(appId);
|
||||||
if (app && typeof app.refresh === "function") {
|
if (app && typeof app.refresh === "function") {
|
||||||
app.refresh();
|
app.refresh();
|
||||||
}
|
}
|
||||||
@@ -419,9 +429,7 @@ export class HelpersL5r5e {
|
|||||||
*/
|
*/
|
||||||
static refreshLocalAndSocket(appId) {
|
static refreshLocalAndSocket(appId) {
|
||||||
game.l5r5e.sockets.refreshAppId(appId);
|
game.l5r5e.sockets.refreshAppId(appId);
|
||||||
Object.values(ui.windows)
|
this.getApplication(appId)?.refresh();
|
||||||
.find((e) => e.id === appId)
|
|
||||||
?.refresh();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ export default class HooksL5r5e {
|
|||||||
|
|
||||||
// Settings TN and EncounterType
|
// Settings TN and EncounterType
|
||||||
if (game.user.isGM) {
|
if (game.user.isGM) {
|
||||||
new game.l5r5e.GmToolbox().render(true);
|
new game.l5r5e.GmToolbox().render(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ***** UI *****
|
// ***** UI *****
|
||||||
@@ -544,4 +544,11 @@ export default class HooksL5r5e {
|
|||||||
|
|
||||||
await game.user.assignHotbarMacro(macro, slot);
|
await game.user.assignHotbarMacro(macro, slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async createCombatant(document, options, userId) {
|
||||||
|
|
||||||
|
console.log(document, options, userId);
|
||||||
|
|
||||||
|
new game.l5r5e.CombatActions().render(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ export class SocketHandlerL5r5e {
|
|||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
_onRefreshAppId(payload) {
|
_onRefreshAppId(payload) {
|
||||||
const app = Object.values(ui.windows).find((e) => e.id === payload.appId);
|
const app = game.l5r5e.HelpersL5r5e.getApplication(payload.appId);
|
||||||
if (!app || typeof app.refresh !== "function") {
|
if (!app || typeof app.refresh !== "function") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -96,7 +96,7 @@ export class SocketHandlerL5r5e {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
_onUpdateMessageIdAndRefresh(payload) {
|
_onUpdateMessageIdAndRefresh(payload) {
|
||||||
const app = Object.values(ui.windows).find((e) => e.id === payload.appId);
|
const app = game.l5r5e.HelpersL5r5e.getApplication(payload.appId);
|
||||||
if (!app || !app.message || typeof app.refresh !== "function") {
|
if (!app || !app.message || typeof app.refresh !== "function") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
@import "../scss/cursors";
|
@import "../scss/cursors";
|
||||||
@import "../scss/dices";
|
@import "../scss/dices";
|
||||||
@import "../scss/ui";
|
@import "../scss/ui";
|
||||||
|
@import "../scss/global-appv2.scss";
|
||||||
|
|
||||||
.l5r5e {
|
.l5r5e {
|
||||||
@import "../scss/dices-chat";
|
@import "../scss/dices-chat";
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
51
system/styles/scss/global-appv2.scss
Normal file
51
system/styles/scss/global-appv2.scss
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
.application {
|
||||||
|
background: unset;
|
||||||
|
color: var(--color-text-dark-primary);
|
||||||
|
|
||||||
|
.scrollable {
|
||||||
|
--scroll-margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.window-header {
|
||||||
|
background: linear-gradient(
|
||||||
|
$l5r5e-linear-gradient-second,
|
||||||
|
$l5r5e-linear-gradient-second-dark,
|
||||||
|
$l5r5e-linear-gradient-second
|
||||||
|
);
|
||||||
|
.window-title {
|
||||||
|
font-family: $font-secondary;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.window-content {
|
||||||
|
background: rgb(255, 250, 230) url("../assets/imgs/bg-l5r.webp") no-repeat;
|
||||||
|
padding: 0.25rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// More specifified stuff down here as to not make it too hard to read the overriden defaults
|
||||||
|
.application {
|
||||||
|
.window-content {
|
||||||
|
table {
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid $l5r5e-title;
|
||||||
|
thead {
|
||||||
|
background: $l5r5e-title;
|
||||||
|
color: $l5r5e-label;
|
||||||
|
text-shadow: none;
|
||||||
|
border-bottom: $l5r5e-title;
|
||||||
|
}
|
||||||
|
tbody {
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
&:nth-child(odd) {
|
||||||
|
background: $l5r5e-odd;
|
||||||
|
}
|
||||||
|
&:nth-child(even) {
|
||||||
|
background: $l5r5e-even;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -860,6 +860,13 @@ button {
|
|||||||
min-width: 240px;
|
min-width: 240px;
|
||||||
|
|
||||||
.window-content {
|
.window-content {
|
||||||
|
[data-application-part="hidden_tabs"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
margin: 0;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
form {
|
form {
|
||||||
padding: 0 0.5rem;
|
padding: 0 0.5rem;
|
||||||
}
|
}
|
||||||
@@ -895,47 +902,39 @@ button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#l5r5e-gm-toolbox {
|
#l5r5e-gm-toolbox {
|
||||||
//bottom: 0;
|
|
||||||
//right: 0.5rem;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
background-position: center;
|
|
||||||
background-size: 100%;
|
|
||||||
background: linear-gradient(
|
background: linear-gradient(
|
||||||
$l5r5e-linear-gradient-second,
|
$l5r5e-linear-gradient-second,
|
||||||
$l5r5e-linear-gradient-second-dark,
|
$l5r5e-linear-gradient-second-dark,
|
||||||
$l5r5e-linear-gradient-second
|
$l5r5e-linear-gradient-second
|
||||||
);
|
);
|
||||||
background-origin: padding-box;
|
|
||||||
border: 1px solid rgb(195, 165, 130);
|
border: 1px solid rgb(195, 165, 130);
|
||||||
background-origin: padding-box;
|
|
||||||
border-image: url("../assets/ui/macro-button.webp") 10 repeat;
|
|
||||||
border-image-width: 0.5rem;
|
|
||||||
border-image-outset: 0px;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0.5rem;
|
margin: 0.5rem;
|
||||||
.window-header {
|
.window-header {
|
||||||
text-align: center;
|
|
||||||
border-bottom: 1px solid rgb(195, 165, 130);
|
border-bottom: 1px solid rgb(195, 165, 130);
|
||||||
h4 {
|
background: none; //keep the same background as the toolbox, not the default black opaque
|
||||||
|
.window-title {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
letter-spacing: 0.25rem;
|
letter-spacing: 0.25rem;
|
||||||
line-height: 2.25rem;
|
line-height: 2.25rem;
|
||||||
color: $white-light;
|
color: $white-light;
|
||||||
|
padding-top: 1ch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.window-content {
|
.window-content {
|
||||||
text-align: center;
|
background: none;
|
||||||
vertical-align: middle;
|
padding: 0;
|
||||||
background: transparent;
|
|
||||||
color: $white-light;
|
|
||||||
form {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
.gm-tools-container {
|
.gm-tools-container {
|
||||||
|
color: var(--color-text-primary);
|
||||||
display: flex;
|
display: flex;
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
line-height: 2rem;
|
line-height: 2rem;
|
||||||
min-height: 2rem;
|
min-height: 2rem;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
li {
|
li {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
<form class="l5r5e gm-toolbox" autocomplete="off">
|
<form class="l5r5e gm-toolbox" autocomplete="off">
|
||||||
<ul class="gm-tools-container">
|
<ul class="gm-tools-container">
|
||||||
<li class="gm_monitor" title="{{localize 'l5r5e.gm.monitor.title'}}">
|
<li class="gm_monitor" data-action="open_gm_monitor" title="{{localize 'l5r5e.gm.monitor.title'}}">
|
||||||
<i class="fas fa-table"></i>
|
<i class="fas fa-table"></i>
|
||||||
</li>
|
</li>
|
||||||
<li class="difficulty_hidden" title="{{localize 'l5r5e.gm.toolbox.difficulty_hidden'}}">
|
<li class="difficulty_hidden" data-action="toggle_hide_difficulty" title="{{localize 'l5r5e.gm.toolbox.difficulty_hidden'}}">
|
||||||
<i class="fa fa-eye{{#if data.difficultyHidden}}-slash{{/if}}"></i>
|
<i class="fa fa-eye{{#if difficultyHidden}}-slash{{/if}}"></i>
|
||||||
<strong class="difficulty" title="{{localize 'l5r5e.gm.toolbox.difficulty'}}">{{data.difficulty}}</strong>
|
<strong class="difficulty" data-action="change_difficulty" title="{{localize 'l5r5e.gm.toolbox.difficulty'}}">{{difficulty}}</strong>
|
||||||
</li>
|
</li>
|
||||||
<li class="gm_actor_updates reset_void" data-type="reset_void" title="{{localize 'l5r5e.gm.toolbox.reset_void'}}">
|
<li class="gm_actor_updates reset_void" data-action="reset_void" title="{{localize 'l5r5e.gm.toolbox.reset_void'}}">
|
||||||
<i class="fas fa-podcast"></i>
|
<i class="fas fa-podcast"></i>
|
||||||
</li>
|
</li>
|
||||||
<li class="gm_actor_updates sleep" data-type="sleep" title="{{localize 'l5r5e.gm.toolbox.sleep'}}">
|
<li class="gm_actor_updates sleep" data-action="sleep" title="{{localize 'l5r5e.gm.toolbox.sleep'}}">
|
||||||
<i class="fa fa-bed"></i>
|
<i class="fa fa-bed"></i>
|
||||||
</li>
|
</li>
|
||||||
<li class="gm_actor_updates scene_end" data-type="scene_end" title="{{localize 'l5r5e.gm.toolbox.scene_end'}}">
|
<li class="gm_actor_updates scene_end" data-action="scene_end" title="{{localize 'l5r5e.gm.toolbox.scene_end'}}">
|
||||||
<i class="fas fa-star-half-alt"></i>
|
<i class="fas fa-star-half-alt"></i>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
55
system/templates/gm/monitor/army-view.html
Normal file
55
system/templates/gm/monitor/army-view.html
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<section class="tab standard-form scrollable {{tabs.army.cssClass}}"
|
||||||
|
data-tab="army" data-group="{{tabs.army.group}}">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<th class="img"></th>
|
||||||
|
<th class="name">{{localize 'l5r5e.sheets.name'}}</th>
|
||||||
|
<th class="warlord">{{localize 'l5r5e.army.warlord'}}</th>
|
||||||
|
<th class="casualties"><i class="fas fa-user-injured" title="{{localize 'l5r5e.army.battle_readiness.casualties'}}"></i> / <i class="fas fa-fist-raised" title="{{localize 'l5r5e.army.battle_readiness.strength'}}"></i></th>
|
||||||
|
<th class="panic"><i class="fas fa-ghost" title="{{localize 'l5r5e.army.battle_readiness.panic'}}"></i> / <i class="fas fa-user-friends" title="{{localize 'l5r5e.army.battle_readiness.discipline'}}"></i></th>
|
||||||
|
<th class="commander">{{localize 'l5r5e.army.commander'}} {{localize 'l5r5e.gm.monitor.honor_glory_status'}}</th>
|
||||||
|
<th class=""></th>
|
||||||
|
<th class=""></th>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{#each armies as |army|}}
|
||||||
|
<tr>
|
||||||
|
<td><img data-actor-uuid="{{army.uuid}}" draggable="true" class="profile actor-profile dragndrop-actor-uuid pointer" title="{{army.name}}" src="{{army.img}}"></td>
|
||||||
|
<td><a data-uuid="{{army.uuid}}" class="open-sheet-from-uuid">{{army.name}}</a></td>
|
||||||
|
<td>
|
||||||
|
{{#if army.system.warlord_actor_id}}
|
||||||
|
<a data-actor-id="{{army.system.warlord_actor_id}}" class="open-sheet-from-uuid">{{army.system.warlord}}</a>
|
||||||
|
{{else}}
|
||||||
|
{{army.system.warlord}}
|
||||||
|
{{/if}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a title="{{localize 'l5r5e.gm.monitor.mouse_control'}}" data-actor-uuid="{{army.uuid}}" data-action="modify_casualties" class="actor-modify-control">
|
||||||
|
<span class="{{#ifCond army.system.battle_readiness.casualties_strength.value '>' army.system.battle_readiness.casualties_strength.max}}badvalue{{/ifCond}}">{{army.system.battle_readiness.casualties_strength.value}}</span>
|
||||||
|
/ {{army.system.battle_readiness.casualties_strength.max}}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a title="{{localize 'l5r5e.gm.monitor.mouse_control'}}" data-actor-uuid="{{army.uuid}}" data-action="modify_panic" class="actor-modify-control">
|
||||||
|
<span class="{{#ifCond army.system.battle_readiness.panic_discipline.value '>' army.system.battle_readiness.panic_discipline.max}}badvalue{{/ifCond}}">{{army.system.battle_readiness.panic_discipline.value}}</span>
|
||||||
|
/ {{army.system.battle_readiness.panic_discipline.max}}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{#if army.system.commander_actor_id}}
|
||||||
|
<a data-actor-id="{{army.system.commander_actor_id}}" class="open-sheet-from-uuid">{{army.system.commander}}</a>
|
||||||
|
{{else}}
|
||||||
|
{{army.system.commander}}
|
||||||
|
{{/if}}
|
||||||
|
<br>
|
||||||
|
<span class="{{#ifCond army.system.commander_standing.honor '>' 64}}goodvalue{{/ifCond}}{{#ifCond army.system.commander_standing.honor '<' 30}}badvalue{{/ifCond}}">{{army.system.commander_standing.honor}}</span>
|
||||||
|
/ <span class="{{#ifCond army.system.commander_standing.glory '>' 64}}goodvalue{{/ifCond}}{{#ifCond army.system.commander_standing.glory '<' 20}}badvalue{{/ifCond}}">{{army.system.commander_standing.glory}}</span>
|
||||||
|
/ {{army.system.commander_standing.status}}
|
||||||
|
</td>
|
||||||
|
<td><i data-actor-uuid="{{army.uuid}}" data-type="global" class="fas fa-question-circle actor-infos-control"></i></td>
|
||||||
|
<td><span data-actor-uuid="{{army.uuid}}" data-action="remove_actor" class="actor-remove-control pointer" title="{{localize 'Delete'}}"><i class="fas fa-trash"></i></span></td>
|
||||||
|
</tr>
|
||||||
|
{{/each}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</section>
|
||||||
85
system/templates/gm/monitor/character-view.html
Normal file
85
system/templates/gm/monitor/character-view.html
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
<section class="tab standard-form scrollable {{tabs.character.cssClass}}"
|
||||||
|
data-tab="character" data-group="{{tabs.character.group}}">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<th class="img"></th>
|
||||||
|
<th class="name">{{localize 'l5r5e.sheets.name'}}</th>
|
||||||
|
<th class="stance"><i class="i_earth"></i></th>
|
||||||
|
<th class="prepared"><i class="fas prepared-icon-true"></i></th>
|
||||||
|
<th class="weapon"><i class="fas fa-fan"></i></th>
|
||||||
|
<th class="armor"><i class="fas fa-user-shield"></i></th>
|
||||||
|
<th class="rank">{{localize 'l5r5e.sheets.rank'}}</th>
|
||||||
|
<th class="fatigue">{{localize 'l5r5e.attributes.fatigue'}}</th>
|
||||||
|
<th class="strife">{{localize 'l5r5e.attributes.strife'}}</th>
|
||||||
|
<th class="vigilance">{{localize 'l5r5e.gm.monitor.focus_vigilance'}}</th>
|
||||||
|
<th class="void"><i class="i_void"></i></th>
|
||||||
|
<th class=""></th>
|
||||||
|
<th class=""></th>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{#each characters as |actor|}}
|
||||||
|
<tr>
|
||||||
|
<td><img data-actor-uuid="{{actor.uuid}}" draggable="true" class="profile actor-profile dragndrop-actor-uuid pointer" title="{{actor.name}}" src="{{actor.img}}"></td>
|
||||||
|
<td>
|
||||||
|
<a data-uuid="{{actor.uuid}}" class="open-sheet-from-uuid">{{actor.name}}</a>
|
||||||
|
{{#if actor.system.attitude}}<p>({{actor.system.attitude}})</p>{{/if}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a data-actor-uuid="{{actor.uuid}}" class="actor-modify-control" data-action="change_stance">
|
||||||
|
<i data-type="text" data-text="<h2>{{localize 'l5r5e.conflict.stance'}} ({{localizeRing actor.system.stance}} - {{lookup actor.system.rings actor.system.stance}})</h2>{{localizeStanceTip actor.system.stance}}" class="i_{{actor.system.stance}} actor-infos-control"></i>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a data-actor-uuid="{{actor.uuid}}" class="actor-modify-control" data-action="toggle_prepared">
|
||||||
|
<i data-type="text" data-text="<h2>{{localize 'l5r5e.conflict.initiative.title'}} : {{localize (localize 'l5r5e.conflict.initiative.prepared_{value}' value=actor.isPrepared)}}</h2>" class="fa fas prepared-icon-{{actor.isPrepared}} {{#ifCond actor.isPrepared '==' 'false'}}badvalue{{/ifCond}} actor-infos-control"></i>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>{{#if actor.haveWeaponEquipped}}<i data-type="weapons" data-actor-uuid="{{actor.uuid}}" class="fas fa-fan actor-infos-control {{#if actor.haveWeaponReadied}}badvalue{{/if}}"></i>{{/if}}</td>
|
||||||
|
<td>{{#if actor.haveArmorEquipped}}<i data-type="armors" data-actor-uuid="{{actor.uuid}}" class="fas fa-user-shield actor-infos-control"></i>{{/if}}</td>
|
||||||
|
<td>
|
||||||
|
<p>
|
||||||
|
{{#if actor.system.identity.school_rank}}
|
||||||
|
{{actor.system.identity.school_rank}}
|
||||||
|
{{else}}
|
||||||
|
<i class="i_bushi" title="{{localize 'l5r5e.social.npc.combat'}}"></i> {{actor.system.conflict_rank.martial}} <i class="i_courtier" title="{{localize 'l5r5e.social.npc.intrigue'}}"></i> {{actor.system.conflict_rank.social}}
|
||||||
|
{{/if}}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
{{#if actor.system.rings_affinities}}
|
||||||
|
{{#each actor.system.rings_affinities as |ringValue ringId|}}
|
||||||
|
{{#if ringValue}}
|
||||||
|
<i class="i_{{ringId}}" title="{{localizeRing ringId}}"></i> {{ringValue}}
|
||||||
|
{{/if}}
|
||||||
|
{{/each}}
|
||||||
|
{{/if}}
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a title="{{localize 'l5r5e.gm.monitor.mouse_control'}}" data-actor-uuid="{{actor.uuid}}" data-action="modify_fatigue" class="actor-modify-control">
|
||||||
|
<span class="{{#ifCond actor.system.fatigue.value '>' actor.system.fatigue.max}}badvalue{{/ifCond}}">{{actor.system.fatigue.value}}</span>
|
||||||
|
/ {{actor.system.fatigue.max}}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a title="{{localize 'l5r5e.gm.monitor.mouse_control'}}" data-actor-uuid="{{actor.uuid}}" data-action="modify_strife" class="actor-modify-control">
|
||||||
|
<span class="{{#ifCond actor.system.strife.value '>' actor.system.strife.max}}badvalue{{/ifCond}}">{{actor.system.strife.value}}</span>
|
||||||
|
/ {{actor.system.strife.max}}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{actor.system.focus}}
|
||||||
|
/ {{#if actor.system.is_compromised}}<span class="badvalue">1</span>{{else}}{{actor.system.vigilance}}{{/if}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a title="{{localize 'l5r5e.gm.monitor.mouse_control'}}" data-actor-uuid="{{actor.uuid}}" data-action="modify_voidPoint" class="actor-modify-control">
|
||||||
|
{{actor.system.void_points.value}}
|
||||||
|
/ {{actor.system.void_points.max}}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td><i data-actor-uuid="{{actor.uuid}}" data-type="global" class="fas fa-question-circle actor-infos-control"></i></td>
|
||||||
|
<td><span data-actor-uuid="{{actor.uuid}}" class="actor-remove-control pointer" data-action="remove_actor" title="{{localize 'Delete'}}"><i class="fas fa-trash"></i></span></td>
|
||||||
|
</tr>
|
||||||
|
{{/each}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</section>
|
||||||
Reference in New Issue
Block a user