mirror of
https://github.com/RoY7x/worldbuilding.git
synced 2025-04-30 02:31:41 -04:00
Merge branch '9-actor-templates-integration' into 'master'
9: Add actor templates See merge request foundrynet/worldbuilding!8
This commit is contained in:
commit
c515f8d5b7
10 changed files with 270 additions and 85 deletions
|
@ -9,5 +9,9 @@
|
|||
|
||||
"SIMPLE.ResourceMin": "Min",
|
||||
"SIMPLE.ResourceValue": "Value",
|
||||
"SIMPLE.ResourceMax": "Max"
|
||||
"SIMPLE.ResourceMax": "Max",
|
||||
|
||||
"SIMPLE.DefineTemplate": "Define as Template",
|
||||
"SIMPLE.UnsetTemplate": "Unset Template",
|
||||
"SIMPLE.NoTemplate": "No Template"
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
import { ATTRIBUTE_TYPES } from "./constants.js";
|
||||
|
||||
/**
|
||||
* Extend the basic ActorSheet with some very simple modifications
|
||||
* @extends {ActorSheet}
|
||||
|
@ -21,7 +23,7 @@ export class SimpleActorSheet extends ActorSheet {
|
|||
/** @override */
|
||||
getData() {
|
||||
const data = super.getData();
|
||||
data.dtypes = ["String", "Number", "Boolean", "Formula", "Resource"];
|
||||
data.dtypes = ATTRIBUTE_TYPES;
|
||||
for ( let attr of Object.values(data.data.attributes) ) {
|
||||
attr.isCheckbox = attr.dtype === "Boolean";
|
||||
attr.isResource = attr.dtype === "Resource";
|
||||
|
|
1
module/constants.js
Normal file
1
module/constants.js
Normal file
|
@ -0,0 +1 @@
|
|||
export const ATTRIBUTE_TYPES = ["String", "Number", "Boolean", "Formula", "Resource"];
|
|
@ -1,3 +1,5 @@
|
|||
import { ATTRIBUTE_TYPES } from "./constants.js";
|
||||
|
||||
/**
|
||||
* Extend the basic ItemSheet with some very simple modifications
|
||||
* @extends {ItemSheet}
|
||||
|
@ -20,7 +22,7 @@ export class SimpleItemSheet extends ItemSheet {
|
|||
/** @override */
|
||||
getData() {
|
||||
const data = super.getData();
|
||||
data.dtypes = ["String", "Number", "Boolean", "Formula", "Resource"];
|
||||
data.dtypes = ATTRIBUTE_TYPES;
|
||||
for ( let attr of Object.values(data.data.attributes) ) {
|
||||
attr.isCheckbox = attr.dtype === "Boolean";
|
||||
attr.isResource = attr.dtype === "Resource";
|
||||
|
|
181
module/simple.js
181
module/simple.js
|
@ -8,6 +8,7 @@
|
|||
import { SimpleActor } from "./actor.js";
|
||||
import { SimpleItemSheet } from "./item-sheet.js";
|
||||
import { SimpleActorSheet } from "./actor-sheet.js";
|
||||
import { preloadHandlebarsTemplates } from "./templates.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Foundry VTT Initialization */
|
||||
|
@ -89,4 +90,184 @@ Hooks.once("init", async function() {
|
|||
return value.slugify({strict: true});
|
||||
});
|
||||
|
||||
// Preload template partials.
|
||||
preloadHandlebarsTemplates();
|
||||
});
|
||||
|
||||
/**
|
||||
* Adds the actor template context menu.
|
||||
*/
|
||||
Hooks.on("getActorDirectoryEntryContext", (html, options) => {
|
||||
// Define an actor as a template.
|
||||
options.push({
|
||||
name: game.i18n.localize("SIMPLE.DefineTemplate"),
|
||||
icon: '<i class="fas fa-stamp"></i>',
|
||||
condition: li => {
|
||||
const actor = game.actors.get(li.data("entityId"));
|
||||
return !actor.getFlag("worldbuilding", "isTemplate");
|
||||
},
|
||||
callback: li => {
|
||||
const actor = game.actors.get(li.data("entityId"));
|
||||
actor.setFlag("worldbuilding", "isTemplate", true);
|
||||
}
|
||||
});
|
||||
|
||||
// Undefine an actor as a template.
|
||||
options.push({
|
||||
name: game.i18n.localize("SIMPLE.UnsetTemplate"),
|
||||
icon: '<i class="fas fa-times"></i>',
|
||||
condition: li => {
|
||||
const actor = game.actors.get(li.data("entityId"));
|
||||
return actor.getFlag("worldbuilding", "isTemplate");
|
||||
},
|
||||
callback: li => {
|
||||
const actor = game.actors.get(li.data("entityId"));
|
||||
actor.setFlag("worldbuilding", "isTemplate", false);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Adds the item template context menu.
|
||||
*/
|
||||
Hooks.on("getItemDirectoryEntryContext", (html, options) => {
|
||||
// Define an item as a template.
|
||||
options.push({
|
||||
name: game.i18n.localize("SIMPLE.DefineTemplate"),
|
||||
icon: '<i class="fas fa-stamp"></i>',
|
||||
condition: li => {
|
||||
const item = game.items.get(li.data("entityId"));
|
||||
return !item.getFlag("worldbuilding", "isTemplate");
|
||||
},
|
||||
callback: li => {
|
||||
const item = game.items.get(li.data("entityId"));
|
||||
item.setFlag("worldbuilding", "isTemplate", true);
|
||||
}
|
||||
});
|
||||
|
||||
// Undefine an item as a template.
|
||||
options.push({
|
||||
name: game.i18n.localize("SIMPLE.UnsetTemplate"),
|
||||
icon: '<i class="fas fa-times"></i>',
|
||||
condition: li => {
|
||||
const item = game.items.get(li.data("entityId"));
|
||||
return item.getFlag("worldbuilding", "isTemplate");
|
||||
},
|
||||
callback: li => {
|
||||
const item = game.items.get(li.data("entityId"));
|
||||
item.setFlag("worldbuilding", "isTemplate", false);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Adds the actor template selection dialog.
|
||||
*/
|
||||
ActorDirectory.prototype._onCreate = async (event) => {
|
||||
// Do not allow the creation event to bubble to other listeners
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
_simpleDirectoryTemplates('actor');
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the item template selection dialog.
|
||||
*/
|
||||
ItemDirectory.prototype._onCreate = async (event) => {
|
||||
// Do not allow the creation event to bubble to other listeners
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
_simpleDirectoryTemplates('item');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the entity template dialog.
|
||||
*
|
||||
* Helper function to display a dialog if there are multiple template types
|
||||
* defined for the entity type.
|
||||
*
|
||||
* @param {string} entityType - 'actor' or 'item'
|
||||
*/
|
||||
async function _simpleDirectoryTemplates(entityType = 'actor') {
|
||||
// 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.
|
||||
let entities = entityCollection.filter(a => a.data.flags?.worldbuilding?.isTemplate === true);
|
||||
|
||||
// Initialize variables related to the entity class.
|
||||
let ent = game.i18n.localize(cls.config.label);
|
||||
|
||||
// Setup entity data.
|
||||
let type = entityType == 'actor' ? 'character' : 'item';
|
||||
let createData = {
|
||||
name: `New ${ent}`,
|
||||
type: type,
|
||||
folder: event.currentTarget.dataset.folder
|
||||
};
|
||||
|
||||
// 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.
|
||||
let types = [{
|
||||
value: null,
|
||||
label: game.i18n.localize("SIMPLE.NoTemplate")
|
||||
}];
|
||||
|
||||
// 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
|
||||
new Dialog({
|
||||
title: `Create ${createData.name}`,
|
||||
content: dlg,
|
||||
buttons: {
|
||||
create: {
|
||||
icon: '<i class="fas fa-check"></i>',
|
||||
label: `Create ${ent}`,
|
||||
callback: html => {
|
||||
// Get the form data.
|
||||
const form = html[0].querySelector("form");
|
||||
mergeObject(createData, validateForm(form));
|
||||
|
||||
// Store the type and name values, and retrieve the template entity.
|
||||
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;
|
||||
}
|
||||
// Otherwise, restore to a valid entity type (character/item).
|
||||
else {
|
||||
createData.type = type;
|
||||
}
|
||||
|
||||
cls.create(createData, {renderSheet: true});
|
||||
}
|
||||
}
|
||||
},
|
||||
default: "create"
|
||||
}).render(true);
|
||||
}
|
||||
// Otherwise, just create a blank entity.
|
||||
else {
|
||||
cls.create(createData, {renderSheet: true});
|
||||
}
|
||||
}
|
16
module/templates.js
Normal file
16
module/templates.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
/**
|
||||
* Define a set of template paths to pre-load
|
||||
* Pre-loaded templates are compiled and cached for fast access when rendering
|
||||
* @return {Promise}
|
||||
*/
|
||||
export const preloadHandlebarsTemplates = async function() {
|
||||
|
||||
// Define template paths to load
|
||||
const templatePaths = [
|
||||
// Attribute list partial.
|
||||
"systems/worldbuilding/templates/parts/sheet-attributes.html"
|
||||
];
|
||||
|
||||
// Load the template parts
|
||||
return loadTemplates(templatePaths);
|
||||
};
|
|
@ -73,47 +73,8 @@
|
|||
<a class="attribute-control" data-action="create"><i class="fas fa-plus"></i></a>
|
||||
</header>
|
||||
|
||||
<ol class="attributes-list">
|
||||
{{#each data.attributes as |attr key|}}
|
||||
<li class="attribute flexrow" data-attribute="{{key}}">
|
||||
<input class="attribute-key" type="text" name="data.attributes.{{key}}.key" value="{{key}}"/>
|
||||
{{!-- Handle booleans. --}}
|
||||
{{#if attr.isCheckbox}}
|
||||
<label class="attribute-value checkbox"><input type="checkbox" name="data.attributes.{{key}}.value" {{checked attr.value}}/></label>
|
||||
{{else}}
|
||||
{{!-- Handle resources. --}}
|
||||
{{#if attr.isResource}}
|
||||
<div class="attribute-group flexrow">
|
||||
<span class="attribute-col flexcol">
|
||||
<label for="data.attributes.{{key}}.min">{{localize "SIMPLE.ResourceMin"}}</label>
|
||||
<input class="attribute-value" type="text" name="data.attributes.{{key}}.min" value="{{attr.min}}" data-dtype="{{attr.dtype}}"/>
|
||||
</span>
|
||||
<span class="attribute-col flexcol">
|
||||
<label for="data.attributes.{{key}}.value">{{localize "SIMPLE.ResourceValue"}}</label>
|
||||
<input class="attribute-value" type="text" name="data.attributes.{{key}}.value" value="{{attr.value}}" data-dtype="{{attr.dtype}}"/>
|
||||
</span>
|
||||
<span class="attribute-col flexcol">
|
||||
<label for="data.attributes.{{key}}.max">{{localize "SIMPLE.ResourceMax"}}</label>
|
||||
<input class="attribute-value" type="text" name="data.attributes.{{key}}.max" value="{{attr.max}}" data-dtype="{{attr.dtype}}"/>
|
||||
</span>
|
||||
</div>
|
||||
{{!-- Handle other input types. --}}
|
||||
{{else}}
|
||||
<input class="attribute-value" type="text" name="data.attributes.{{key}}.value" value="{{attr.value}}" data-dtype="{{attr.dtype}}"/>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
<input class="attribute-label" type="text" name="data.attributes.{{key}}.label" value="{{attr.label}}"/>
|
||||
<select class="attribute-dtype" name="data.attributes.{{key}}.dtype">
|
||||
{{#select attr.dtype}}
|
||||
{{#each ../dtypes as |t|}}
|
||||
<option value="{{t}}">{{t}}</option>
|
||||
{{/each}}
|
||||
{{/select}}
|
||||
</select>
|
||||
<a class="attribute-control" data-action="delete"><i class="fas fa-trash"></i></a>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ol>
|
||||
{{!-- Render the attribute list partial. --}}
|
||||
{{> "systems/worldbuilding/templates/parts/sheet-attributes.html" attributes=data.attributes dtypes=dtypes}}
|
||||
</div>
|
||||
</section>
|
||||
</form>
|
||||
|
|
|
@ -38,47 +38,8 @@
|
|||
<a class="attribute-control" data-action="create"><i class="fas fa-plus"></i></a>
|
||||
</header>
|
||||
|
||||
<ol class="attributes-list">
|
||||
{{#each data.attributes as |attr key|}}
|
||||
<li class="attribute flexrow" data-attribute="{{key}}">
|
||||
<input class="attribute-key" type="text" name="data.attributes.{{key}}.key" value="{{key}}"/>
|
||||
{{!-- Handle booleans. --}}
|
||||
{{#if attr.isCheckbox}}
|
||||
<label class="attribute-value checkbox"><input type="checkbox" name="data.attributes.{{key}}.value" {{checked attr.value}}/></label>
|
||||
{{else}}
|
||||
{{!-- Handle resources. --}}
|
||||
{{#if attr.isResource}}
|
||||
<div class="attribute-group flexrow">
|
||||
<span class="attribute-col flexcol">
|
||||
<label for="data.attributes.{{key}}.min">Min</label>
|
||||
<input class="attribute-value" type="text" name="data.attributes.{{key}}.min" value="{{attr.min}}" data-dtype="{{attr.dtype}}"/>
|
||||
</span>
|
||||
<span class="attribute-col flexcol">
|
||||
<label for="data.attributes.{{key}}.value">Current</label>
|
||||
<input class="attribute-value" type="text" name="data.attributes.{{key}}.value" value="{{attr.value}}" data-dtype="{{attr.dtype}}"/>
|
||||
</span>
|
||||
<span class="attribute-col flexcol">
|
||||
<label for="data.attributes.{{key}}.max">Max</label>
|
||||
<input class="attribute-value" type="text" name="data.attributes.{{key}}.max" value="{{attr.max}}" data-dtype="{{attr.dtype}}"/>
|
||||
</span>
|
||||
</div>
|
||||
{{!-- Handle other input types. --}}
|
||||
{{else}}
|
||||
<input class="attribute-value" type="text" name="data.attributes.{{key}}.value" value="{{attr.value}}" data-dtype="{{attr.dtype}}"/>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
<input class="attribute-label" type="text" name="data.attributes.{{key}}.label" value="{{attr.label}}"/>
|
||||
<select class="attribute-dtype" name="data.attributes.{{key}}.dtype">
|
||||
{{#select attr.dtype}}
|
||||
{{#each ../dtypes as |t|}}
|
||||
<option value="{{t}}">{{t}}</option>
|
||||
{{/each}}
|
||||
{{/select}}
|
||||
</select>
|
||||
<a class="attribute-control" data-action="delete"><i class="fas fa-trash"></i></a>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ol>
|
||||
{{!-- Render the attribute list partial. --}}
|
||||
{{> "systems/worldbuilding/templates/parts/sheet-attributes.html" attributes=data.attributes dtypes=dtypes}}
|
||||
</div>
|
||||
</section>
|
||||
</form>
|
||||
|
|
41
templates/parts/sheet-attributes.html
Normal file
41
templates/parts/sheet-attributes.html
Normal file
|
@ -0,0 +1,41 @@
|
|||
<ol class="attributes-list">
|
||||
{{#each attributes as |attr key|}}
|
||||
<li class="attribute flexrow" data-attribute="{{key}}">
|
||||
<input class="attribute-key" type="text" name="data.attributes.{{key}}.key" value="{{key}}"/>
|
||||
{{!-- Handle booleans. --}}
|
||||
{{#if attr.isCheckbox}}
|
||||
<label class="attribute-value checkbox"><input type="checkbox" name="data.attributes.{{key}}.value" {{checked attr.value}}/></label>
|
||||
{{else}}
|
||||
{{!-- Handle resources. --}}
|
||||
{{#if attr.isResource}}
|
||||
<div class="attribute-group flexrow">
|
||||
<span class="attribute-col flexcol">
|
||||
<label for="data.attributes.{{key}}.min">{{localize "SIMPLE.ResourceMin"}}</label>
|
||||
<input class="attribute-value" type="text" name="data.attributes.{{key}}.min" value="{{attr.min}}" data-dtype="{{attr.dtype}}"/>
|
||||
</span>
|
||||
<span class="attribute-col flexcol">
|
||||
<label for="data.attributes.{{key}}.value">{{localize "SIMPLE.ResourceValue"}}</label>
|
||||
<input class="attribute-value" type="text" name="data.attributes.{{key}}.value" value="{{attr.value}}" data-dtype="{{attr.dtype}}"/>
|
||||
</span>
|
||||
<span class="attribute-col flexcol">
|
||||
<label for="data.attributes.{{key}}.max">{{localize "SIMPLE.ResourceMax"}}</label>
|
||||
<input class="attribute-value" type="text" name="data.attributes.{{key}}.max" value="{{attr.max}}" data-dtype="{{attr.dtype}}"/>
|
||||
</span>
|
||||
</div>
|
||||
{{!-- Handle other input types. --}}
|
||||
{{else}}
|
||||
<input class="attribute-value" type="text" name="data.attributes.{{key}}.value" value="{{attr.value}}" data-dtype="{{attr.dtype}}"/>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
<input class="attribute-label" type="text" name="data.attributes.{{key}}.label" value="{{attr.label}}"/>
|
||||
<select class="attribute-dtype" name="data.attributes.{{key}}.dtype">
|
||||
{{#select attr.dtype}}
|
||||
{{#each ../dtypes as |t|}}
|
||||
<option value="{{t}}">{{t}}</option>
|
||||
{{/each}}
|
||||
{{/select}}
|
||||
</select>
|
||||
<a class="attribute-control" data-action="delete"><i class="fas fa-trash"></i></a>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ol>
|
16
templates/sidebar/entity-create.html
Normal file
16
templates/sidebar/entity-create.html
Normal file
|
@ -0,0 +1,16 @@
|
|||
<form id="entity-create" autocomplete="off" onsubmit="event.preventDefault();">
|
||||
<div class="form-group">
|
||||
<label>{{localize "Name"}}</label>
|
||||
<input type="text" name="name" placeholder="{{localize 'ENTITY.CreateNew'}} {{upper}}"/>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>{{localize "Type"}}</label>
|
||||
<select name="type">
|
||||
{{#each types}}
|
||||
<option value="{{this.value}}">{{this.label}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
<p class="notes">{{localize "ENTITY.TypeHint"}}</p>
|
||||
</div>
|
||||
</form>
|
Loading…
Add table
Reference in a new issue