mirror of
https://github.com/RoY7x/worldbuilding.git
synced 2025-04-30 02:31:41 -04:00
Tidy the worldbuilding system for 0.40 release
This commit is contained in:
parent
d641ff96b0
commit
6bf056b3d4
9 changed files with 72 additions and 184 deletions
|
@ -24,11 +24,7 @@ export class SimpleActorSheet extends ActorSheet {
|
||||||
/** @override */
|
/** @override */
|
||||||
getData() {
|
getData() {
|
||||||
const data = super.getData();
|
const data = super.getData();
|
||||||
|
|
||||||
// Handle attribute groups.
|
|
||||||
EntitySheetHelper.getAttributeData(data);
|
EntitySheetHelper.getAttributeData(data);
|
||||||
|
|
||||||
// Add shorthand.
|
|
||||||
data.shorthand = !!game.settings.get("worldbuilding", "macroShorthand");
|
data.shorthand = !!game.settings.get("worldbuilding", "macroShorthand");
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
@ -39,15 +35,13 @@ export class SimpleActorSheet extends ActorSheet {
|
||||||
activateListeners(html) {
|
activateListeners(html) {
|
||||||
super.activateListeners(html);
|
super.activateListeners(html);
|
||||||
|
|
||||||
// Handle rollable items.
|
|
||||||
html.find(".items .rollable").on("click", this._onItemRoll.bind(this));
|
|
||||||
|
|
||||||
// Handle rollable attributes.
|
|
||||||
html.find(".attributes").on("click", "a.attribute-roll", EntitySheetHelper.onAttributeRoll.bind(this));
|
|
||||||
|
|
||||||
// Everything below here is only needed if the sheet is editable
|
// Everything below here is only needed if the sheet is editable
|
||||||
if ( !this.options.editable ) return;
|
if ( !this.options.editable ) return;
|
||||||
|
|
||||||
|
// Handle rollable items and attributes
|
||||||
|
html.find(".items .rollable").on("click", this._onItemRoll.bind(this));
|
||||||
|
html.find(".attributes").on("click", "a.attribute-roll", EntitySheetHelper.onAttributeRoll.bind(this));
|
||||||
|
|
||||||
// Update Inventory Item
|
// Update Inventory Item
|
||||||
html.find('.item-edit').click(ev => {
|
html.find('.item-edit').click(ev => {
|
||||||
const li = $(ev.currentTarget).parents(".item");
|
const li = $(ev.currentTarget).parents(".item");
|
||||||
|
@ -80,36 +74,6 @@ export class SimpleActorSheet extends ActorSheet {
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/** @override */
|
|
||||||
async _onSubmit(event, {updateData=null, preventClose=false, preventRender=false}={}) {
|
|
||||||
let attr = EntitySheetHelper.onSubmit(event);
|
|
||||||
|
|
||||||
// Submit the form if attr is true or an attr key.
|
|
||||||
if ( attr ) {
|
|
||||||
await super._onSubmit(event, {updateData: updateData, preventClose: preventClose, preventRender: preventRender});
|
|
||||||
|
|
||||||
// If attr is a key and not just true, set a very short timeout and retrigger focus after the original element is deleted and the new one is inserted.
|
|
||||||
if ( attr !== true) {
|
|
||||||
setTimeout(() => {
|
|
||||||
$(`input[name="${attr}"]`).parents('.attribute').find('.attribute-value').focus();
|
|
||||||
}, 10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
|
|
||||||
/** @override */
|
|
||||||
setPosition(options={}) {
|
|
||||||
const position = super.setPosition(options);
|
|
||||||
const sheetBody = this.element.find(".sheet-body");
|
|
||||||
const bodyHeight = position.height - 192;
|
|
||||||
sheetBody.css("height", bodyHeight);
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listen for roll buttons on items.
|
* Listen for roll buttons on items.
|
||||||
* @param {MouseEvent} event The originating left click event
|
* @param {MouseEvent} event The originating left click event
|
||||||
|
@ -126,14 +90,12 @@ export class SimpleActorSheet extends ActorSheet {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
_updateObject(event, formData) {
|
_updateObject(event, formData) {
|
||||||
|
|
||||||
// Handle attribute and group updates.
|
|
||||||
formData = EntitySheetHelper.updateAttributes(formData, this);
|
formData = EntitySheetHelper.updateAttributes(formData, this);
|
||||||
formData = EntitySheetHelper.updateGroups(formData, this);
|
formData = EntitySheetHelper.updateGroups(formData, this);
|
||||||
|
|
||||||
// Update the Actor with the new form values.
|
|
||||||
return this.object.update(formData);
|
return this.object.update(formData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -181,7 +181,7 @@ export class EntitySheetHelper {
|
||||||
const label = button.closest(".attribute").querySelector(".attribute-label")?.value;
|
const label = button.closest(".attribute").querySelector(".attribute-label")?.value;
|
||||||
const chatLabel = label ?? button.parentElement.querySelector(".attribute-key").value;
|
const chatLabel = label ?? button.parentElement.querySelector(".attribute-key").value;
|
||||||
const shorthand = game.settings.get("worldbuilding", "macroShorthand");
|
const shorthand = game.settings.get("worldbuilding", "macroShorthand");
|
||||||
const rollData = this.actor.getRollData();
|
const rollData = this.object.getRollData();
|
||||||
let formula = button.closest(".attribute").querySelector(".attribute-value")?.value;
|
let formula = button.closest(".attribute").querySelector(".attribute-value")?.value;
|
||||||
|
|
||||||
// If there's a formula, attempt to roll it.
|
// If there's a formula, attempt to roll it.
|
||||||
|
@ -527,18 +527,14 @@ export class EntitySheetHelper {
|
||||||
if ( typeof formula != "string" || depth < 1) {
|
if ( typeof formula != "string" || depth < 1) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace attributes with their numeric equivalents.
|
// Replace attributes with their numeric equivalents.
|
||||||
let dataRgx = new RegExp(/@([a-z.0-9_\-]+)/gi);
|
let dataRgx = new RegExp(/@([a-z.0-9_\-]+)/gi);
|
||||||
let rollFormula = formula.replace(dataRgx, (match, term) => {
|
let rollFormula = formula.replace(dataRgx, (match, term) => {
|
||||||
// Replace matches with the value, or the missing value.
|
|
||||||
let value = getProperty(data, term);
|
let value = getProperty(data, term);
|
||||||
value = value ? String(value).trim() : (missing != null ? missing : `@${term}`);
|
if ( value === null ) return "0";
|
||||||
// If there's still an attribute in the returned string, nest it in parentheses so that it's evaluated first in the roll.
|
if ( String(value).includes('@') ) return value;
|
||||||
value = value && value.includes('@') ? `(${value})` : value;
|
else return `@${term}`;
|
||||||
return value;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return rollFormula;
|
return rollFormula;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,55 +23,22 @@ export class SimpleItemSheet extends ItemSheet {
|
||||||
/** @override */
|
/** @override */
|
||||||
getData() {
|
getData() {
|
||||||
const data = super.getData();
|
const data = super.getData();
|
||||||
|
|
||||||
// Handle attribute groups.
|
|
||||||
EntitySheetHelper.getAttributeData(data);
|
EntitySheetHelper.getAttributeData(data);
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/** @override */
|
|
||||||
async _onSubmit(event, {updateData=null, preventClose=false, preventRender=false}={}) {
|
|
||||||
let attr = EntitySheetHelper.onSubmit(event);
|
|
||||||
|
|
||||||
// Submit the form if attr is true or an attr key.
|
|
||||||
if ( attr ) {
|
|
||||||
await super._onSubmit(event, {updateData: updateData, preventClose: preventClose, preventRender: preventRender});
|
|
||||||
|
|
||||||
// If attr is a key and not just true, set a very short timeout and retrigger focus after the original element is deleted and the new one is inserted.
|
|
||||||
if ( attr !== true) {
|
|
||||||
setTimeout(() => {
|
|
||||||
$(`input[name="${attr}"]`).parents('.attribute').find('.attribute-value').focus();
|
|
||||||
}, 10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
|
|
||||||
/** @override */
|
|
||||||
setPosition(options={}) {
|
|
||||||
const position = super.setPosition(options);
|
|
||||||
const sheetBody = this.element.find(".sheet-body");
|
|
||||||
const bodyHeight = position.height - 192;
|
|
||||||
sheetBody.css("height", bodyHeight);
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
activateListeners(html) {
|
activateListeners(html) {
|
||||||
super.activateListeners(html);
|
super.activateListeners(html);
|
||||||
|
|
||||||
// Handle rollable attributes.
|
|
||||||
html.find(".attributes").on("click", "a.attribute-roll", EntitySheetHelper.onAttributeRoll.bind(this));
|
|
||||||
|
|
||||||
// Everything below here is only needed if the sheet is editable
|
// Everything below here is only needed if the sheet is editable
|
||||||
if (!this.options.editable) return;
|
if (!this.options.editable) return;
|
||||||
|
|
||||||
|
// Rollable attributes
|
||||||
|
html.find(".attributes").on("click", "a.attribute-roll", EntitySheetHelper.onAttributeRoll.bind(this));
|
||||||
|
|
||||||
// Add draggable for macros.
|
// Add draggable for macros.
|
||||||
html.find(".attributes a.attribute-roll").each((i, a) => {
|
html.find(".attributes a.attribute-roll").each((i, a) => {
|
||||||
a.setAttribute("draggable", true);
|
a.setAttribute("draggable", true);
|
||||||
|
|
100
module/simple.js
100
module/simple.js
|
@ -176,110 +176,66 @@ Hooks.on("getItemDirectoryEntryContext", (html, options) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
async function _onCreateEntity(event) {
|
||||||
* Adds the actor template selection dialog.
|
|
||||||
*/
|
|
||||||
ActorDirectory.prototype._onCreateEntity = async (event) => {
|
|
||||||
// Do not allow the creation event to bubble to other listeners
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
return _simpleDirectoryTemplates(this, event);
|
||||||
_simpleDirectoryTemplates('actor', event);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the item template selection dialog.
|
|
||||||
*/
|
|
||||||
ItemDirectory.prototype._onCreateEntity = async (event) => {
|
|
||||||
// Do not allow the creation event to bubble to other listeners
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
|
|
||||||
_simpleDirectoryTemplates('item', event);
|
|
||||||
}
|
}
|
||||||
|
ActorDirectory.prototype._onCreateEntity = _onCreateEntity; // For 0.7.x+
|
||||||
|
ItemDirectory.prototype._onCreateEntity = _onCreateEntity;
|
||||||
|
ActorDirectory.prototype._onCreate = _onCreateEntity; // TODO: for 0.6.6
|
||||||
|
ItemDirectory.prototype._onCreate = _onCreateEntity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display the entity template dialog.
|
* Display the entity template dialog.
|
||||||
*
|
*
|
||||||
* Helper function to display a dialog if there are multiple template types
|
* Helper function to display a dialog if there are multiple template types defined for the entity type.
|
||||||
* defined for the entity type.
|
* TODO: Refactor in 0.7.x to play more nicely with the Entity.createDialog method
|
||||||
*
|
*1
|
||||||
* @param {string} entityType - 'actor' or 'item'
|
* @param {EntityCollection} entityType - The sidebar tab
|
||||||
* @param {MouseEvent} event - Triggering event
|
* @param {MouseEvent} event - Triggering event
|
||||||
*/
|
*/
|
||||||
async function _simpleDirectoryTemplates(entityType = 'actor', event) {
|
async function _simpleDirectoryTemplates(collection, event) {
|
||||||
// Retrieve the collection and class.
|
|
||||||
const entityCollection = entityType == 'actor' ? game.actors : game.items;
|
|
||||||
const cls = entityType == 'actor' ? Actor : Item;
|
|
||||||
|
|
||||||
// Query for all entities of this type using the "isTemplate" flag.
|
// Retrieve the collection and find any available templates
|
||||||
let entities = entityCollection.filter(a => a.data.flags?.worldbuilding?.isTemplate === true);
|
const entityCollection = collection.tabName === "actors" ? game.actors : game.items;
|
||||||
|
const cls = collection.tabName === "actors" ? Actor : Item;
|
||||||
// Initialize variables related to the entity class.
|
let templates = entityCollection.filter(a => a.getFlag("worldbuilding", "isTemplate"));
|
||||||
let ent = game.i18n.localize(cls.config.label);
|
let ent = game.i18n.localize(cls.config.label);
|
||||||
|
|
||||||
// Setup entity data.
|
// Setup default creation data
|
||||||
let type = entityType == 'actor' ? 'character' : 'item';
|
let type = collection.tabName === "actors" ? 'character' : 'item';
|
||||||
let createData = {
|
let createData = {
|
||||||
name: `${game.i18n.localize("SIMPLE.New")} ${ent}`,
|
name: `${game.i18n.localize("SIMPLE.New")} ${ent}`,
|
||||||
type: type,
|
type: type,
|
||||||
folder: event.currentTarget.dataset.folder
|
folder: event.currentTarget.dataset.folder
|
||||||
};
|
};
|
||||||
|
if ( !templates.length ) return cls.create(createData, {renderSheet: true});
|
||||||
|
|
||||||
// If there's more than one entity template type, create a form.
|
|
||||||
if (entities.length > 0) {
|
|
||||||
// Build an array of types for the form, including an empty default.
|
// Build an array of types for the form, including an empty default.
|
||||||
let types = [{
|
let types = [{
|
||||||
value: null,
|
value: null,
|
||||||
label: game.i18n.localize("SIMPLE.NoTemplate")
|
label: game.i18n.localize("SIMPLE.NoTemplate")
|
||||||
}];
|
}].concat(templates.map(a => { return { value: a.id, label: a.name } }));
|
||||||
|
|
||||||
// Append each of the user-defined actor/item types.
|
|
||||||
types = types.concat(entities.map(a => {
|
|
||||||
return {
|
|
||||||
value: a.data.name,
|
|
||||||
label: a.data.name
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Render the entity creation form
|
|
||||||
let templateData = {upper: ent, lower: ent.toLowerCase(), types: types},
|
|
||||||
dlg = await renderTemplate(`systems/worldbuilding/templates/sidebar/entity-create.html`, templateData);
|
|
||||||
|
|
||||||
// Render the confirmation dialog window
|
// Render the confirmation dialog window
|
||||||
Dialog.confirm({
|
const templateData = {upper: ent, lower: ent.toLowerCase(), types: types};
|
||||||
|
const dlg = await renderTemplate(`systems/worldbuilding/templates/sidebar/entity-create.html`, templateData);
|
||||||
|
return Dialog.confirm({
|
||||||
title: `${game.i18n.localize("SIMPLE.Create")} ${createData.name}`,
|
title: `${game.i18n.localize("SIMPLE.Create")} ${createData.name}`,
|
||||||
content: dlg,
|
content: dlg,
|
||||||
yes: html => {
|
yes: html => {
|
||||||
// Get the form data.
|
|
||||||
const form = html[0].querySelector("form");
|
const form = html[0].querySelector("form");
|
||||||
const fd = new FormDataExtended(form);
|
const template = entityCollection.get(form.type.value);
|
||||||
mergeObject(createData, fd.toObject());
|
if ( template ) {
|
||||||
|
createData = mergeObject(template.data, createData, {inplace: false});
|
||||||
// Store the type and name values, and retrieve the template entity.
|
createData.type = template.data.type;
|
||||||
let templateActor = entityCollection.getName(createData.type);
|
|
||||||
|
|
||||||
// If there's a template entity, handle the data.
|
|
||||||
if (templateActor) {
|
|
||||||
// Update the object with the existing template's values.
|
|
||||||
createData = mergeObject(templateActor.data, createData, {inplace: false});
|
|
||||||
createData.type = templateActor.data.type;
|
|
||||||
// Clear the flag so that this doesn't become a new template.
|
|
||||||
delete createData.flags.worldbuilding.isTemplate;
|
delete createData.flags.worldbuilding.isTemplate;
|
||||||
}
|
}
|
||||||
// Otherwise, restore to a valid entity type (character/item).
|
createData.name = form.name.value;
|
||||||
else {
|
return cls.create(createData, {renderSheet: true});
|
||||||
createData.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
cls.create(createData, {renderSheet: true});
|
|
||||||
},
|
},
|
||||||
no: () => {},
|
no: () => {},
|
||||||
defaultYes: false
|
defaultYes: false
|
||||||
});
|
});
|
||||||
}
|
|
||||||
// Otherwise, just create a blank entity.
|
|
||||||
else {
|
|
||||||
cls.create(createData, {renderSheet: true});
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -8,8 +8,11 @@
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
}
|
}
|
||||||
|
.worldbuilding form {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
.worldbuilding .sheet-header {
|
.worldbuilding .sheet-header {
|
||||||
height: 100px;
|
flex: 0 0 100px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
@ -49,7 +52,7 @@
|
||||||
height: 28px;
|
height: 28px;
|
||||||
}
|
}
|
||||||
.worldbuilding .tabs {
|
.worldbuilding .tabs {
|
||||||
height: 40px;
|
flex: 0 0 40px;
|
||||||
border-top: 1px solid #AAA;
|
border-top: 1px solid #AAA;
|
||||||
border-bottom: 1px solid #AAA;
|
border-bottom: 1px solid #AAA;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,12 @@
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.sheet-header {
|
.sheet-header {
|
||||||
height: 100px;
|
flex: 0 0 100px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
@ -52,7 +56,7 @@
|
||||||
|
|
||||||
/* Sheet Tabs */
|
/* Sheet Tabs */
|
||||||
.tabs {
|
.tabs {
|
||||||
height: 40px;
|
flex: 0 0 40px;
|
||||||
border-top: 1px solid #AAA;
|
border-top: 1px solid #AAA;
|
||||||
border-bottom: 1px solid #AAA;
|
border-bottom: 1px solid #AAA;
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"name": "worldbuilding",
|
"name": "worldbuilding",
|
||||||
"title": "Simple World-Building",
|
"title": "Simple World-Building",
|
||||||
"description": "A minimalist game system with very simple Actor and Item models to support free-form system agnostic gameplay.",
|
"description": "A minimalist game system which provides configurable Actor and Item templates to support free-form system agnostic game-play.",
|
||||||
"version": 0.36,
|
"version": 0.40,
|
||||||
"minimumCoreVersion": "0.7.3",
|
"minimumCoreVersion": "0.6.6",
|
||||||
"compatibleCoreVersion": "0.7.3",
|
"compatibleCoreVersion": "0.7.3",
|
||||||
"templateVersion": 2,
|
"templateVersion": 2,
|
||||||
"author": "Atropos",
|
"author": "Atropos",
|
||||||
|
@ -23,6 +23,6 @@
|
||||||
"secondaryTokenAttribute": "power",
|
"secondaryTokenAttribute": "power",
|
||||||
"url": "https://gitlab.com/foundrynet/worldbuilding/",
|
"url": "https://gitlab.com/foundrynet/worldbuilding/",
|
||||||
"manifest": "https://gitlab.com/foundrynet/worldbuilding/raw/master/system.json",
|
"manifest": "https://gitlab.com/foundrynet/worldbuilding/raw/master/system.json",
|
||||||
"download": "https://gitlab.com/foundrynet/worldbuilding/-/archive/release-036/worldbuilding-release-036.zip",
|
"download": "https://gitlab.com/foundrynet/worldbuilding/-/archive/release-040/worldbuilding-release-040.zip",
|
||||||
"license": "LICENSE.txt"
|
"license": "LICENSE.txt"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<form class="{{cssClass}}" autocomplete="off">
|
<form class="flexcol {{cssClass}}" autocomplete="off">
|
||||||
|
|
||||||
{{!-- Sheet Header --}}
|
{{!-- Sheet Header --}}
|
||||||
<header class="sheet-header">
|
<header class="sheet-header">
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<form class="{{cssClass}}" autocomplete="off">
|
<form class="flexcol {{cssClass}}" autocomplete="off">
|
||||||
<header class="sheet-header">
|
<header class="sheet-header">
|
||||||
<img class="profile-img" src="{{item.img}}" data-edit="img" title="{{item.name}}" />
|
<img class="profile-img" src="{{item.img}}" data-edit="img" title="{{item.name}}" />
|
||||||
<div class="header-fields">
|
<div class="header-fields">
|
||||||
|
|
Loading…
Add table
Reference in a new issue