-
-
Notifications
You must be signed in to change notification settings - Fork 2
How to add system support
- Install the Koboltworks Data Inspector. It's a "must have" for every developer. Also, Alpha Suit integrates with the inspector and adds "inspect" buttons to observe data structure of items. It is especially helpful for compendium entities.
- Basic compendium filters can be done without any coding skills. But more advanced requires some js knowledge. Adding inline "info widgets" or "selected document info pages" needs at least basic Svelte skills.
- The module is based on TyphonJS so you can use its documentation to start working with Alpha Suit. TLDR:
npm install & npm run dev
then openhttp://localhost:30001
- Do not hesitate to ask me anything in Discord: Averrin#0374
- Use
dnd5e
orpf2e
as example. This documentation can be incomplete or outdated. - Filters are based on Filtrex lib. It's necessary to understand its syntax.
- Enable
Browser advanced mode
in Compendium Browser settings. It will help you to debug your filters. - You may be confused by inconsistent using of
data
andsystem
. In general,system
is a modern v10 alternative todata
. In most cases, you still can usedata
. But it doesn't work if we are speaking of compendium indexing. I made a couple of hacks to mitigate this difference. You can use eitherdata
andsystem
everywhere, but directgetIndex
calls. - Unfortunately, most of system-related change will cause full page reloading. And even worse, system-specific widgets requires manual page refresh to apply changes.
We will use pf1
as an example. Please note, at the moment of its writing, this system isn't supported.
- create file
src/systems/pf1.js
(a file name will use only by you for importing)
With content like
import System from "../modules/system.js";
const pf1 = new System({
id: "pf1", //this one MUST be the same as your `game.system.id`
tabs: [],
});
export default pf1;
It's a minimal viable configuration.
- go to
src/systems.js
and add your system like others.
import pf1from "./systems/pf1.js";
addSystem(pf1);
- In the Alpha Browser's tab line, the tag with system ID should become purple instead of red.
- Congratulations, your system is now supported!
- Profit!
First of all, you may want to edit tab set for Compendium Browser. Let's see pf2e
example.
tabs: [
...
{
title: "Items", // Title
icon: "fa-solid:suitcase", // Any Icon id from https://icon-sets.iconify.design
type: "Item", // `metadata.type` of compendium. Will use to filter displayed items
subtypes: ['equipment', 'consumable', 'armor', 'weapon', 'kit', 'treasure', 'backpack'], // list of `type` of items. Also using for filtering. You can omit this field to select all subtypes
},
...
]
This one is quite straightforward but can boost your system experience.
And again, pf2e
for the win.
sortings: {
"Items": [ // reference to the tab's title (yeah, i know, i should make it id, but it's a title right now)
{
label: "type", // displaying sorting's label
query: "@type", // e.g `@data.details.level.value` (see inspector for the right path. Tip: right click in the inspector window will show you path in the input) or it can be an "alias" (see below).
asc: true, desc: true, // showing buttons for each direction
},
],
"NPC": [
{
label: "level",
query: "@level",
asc: true, desc: true,
},
]
},
like here. It can be used in any filtrex query, even in search inputs. Beware, sometimes using a full path is better. I don't remember why and where, sorry.
Note: do not use @
sign in aliases, it using only to replace query part before compilation.
The most complicated part. Please use examples from the actual code, your brain and coding skills.
If you want to tweak some logic, do it here. Yeah, it's a mess, I know. =(
filters: {
"%TAB_NAME%": {
"%FILTER_CATEGORY%": [
{%filter here%}
]
}
}
It's a simple component, but there are some pitfalls.
{
label: "Price (gp)",
control: "compare-int",
attribute: "@data.price.value.gp" // filtrex query
},
{
label: "Weight",
control: "compare-int",
attribute: "float(@data.weight.value)"
},
Sometimes (more often than should be) numeric attributes are stored as strings. For correct results we should convert it into the number. Here is used float
function. You can find list of supported functions here (please, do not click this link, if you wanna keep your mind safe. You are warned.)
If you want to search in somewhat like description, use control: "string"
. It's a very heavy operation, use it wisely.
{
label: "Desc",
control: "string",
attribute: "@data.description.value",
template: "${attribute} ~= \"${value}\"",
},
Here we can see a new "attribute - template" approach. template
is using to build a query using two properties: attribute
from an entity and value
from the control. Watch the quotation marks!
It's simple but flexible control, suitable for boolean comparisons or for the cases where no need for or
logic. There are a couple of different ways to use this control.
{
label: "Attunement",
control: "select",
options: [
{ value: ``, label: "" },
{ value: `@data.attunement != 1`, label: "Not Required" },
{ value: `@data.attunement == 1`, label: "Required" },
]
},
Just inline query as value.
{
label: "Env",
control: "select",
attribute: "@data.details.environment",
options: () => environments,
},
Familiar "attribute" approach and options
as a function. It should to be a function because the environments
variable isn't populated yet and will be built in init
function of the System
itself. Here you can find a couple of examples how to build complex options list from the existing compendium. Sometimes it just too big to be inline.
Now you are more or less familiar with all used concepts.
{
label: "Damage Type",
control: "multiselect",
attribute: "getDamageTypes(@data.damage)",
template: "${value} in ${attribute}",
options: [
{ value: ``, label: "" }, // TODO: add empty option automatically
...damageTypes
], logic: "or"
},
Imported and inlined list of options. Just another way to do it.
logic
is multiselect's specific property. It affects how to build the resulting query when more than one option is selected.
extraInfo: {
"Items": { component: ItemsData, index: ["data.price", "data.weight", "data.armor.value", "data.rarity"] },
"spell": { component: SpellsData },
},
There are two moments simultaneously.
-
"%TAB_NAME%": {}
for the Browser. It's necessary to add all used fields to theindex
property (otherwise unimported entities will be empty). -
"%SUBTYPE%": {}
for the Tree. These entities are imported, so all properties are filled.
Use *Data
components from src/systems/dnd5e
as a reference.
selectedInfo: {
"Actor": {
"npc": { component: SelectedNPC },
"character": { component: SelectedCharacter },
},
"Item": {
"spell": { component: SelectedSpell },
"weapon": { component: SelectedWeapon },
"equipment": { component: SelectedItem },
"loot": { component: SelectedItem },
"tool": { component: SelectedItem },
"consumable": { component: SelectedItem },
"feat": { component: SelectedItem },
}
},
Here is "Type -> Subtype" structure. Please consider the fact that item
is a svelte store. All examples support basic cases of reactive updates of the given item.
Use Selected*
components from src/systems/dnd5e
as a reference.