This module gives you the ability to condense one or more Compendiums of Foundry Items down into a single quick-reference table in a JournalEntry.
It can be useful for any system, but was written for Savage Worlds. Because Savage Worlds is a generic RPG system, playing it often involves navigating lists of gear, skills, etc spanning several books: the core rulebook, then the additions and subtractions made by your setting book, then any further additions from supplements or expansions. This can get awkward.
With this module, you can produce a single, canonical reference for you and your players.
Right now, only SWADE is supported. However the bulk of the code has been written to be system agnostic and adding support for more systems should be as simple as writing some new Handlebars templates. If you're interested in contributing that, please let me know.
I am docg#2827 on Discord. You can ping me in #swade on the FoundryVTT Discord.
Alternatively, you can file an issue in GitHub here. If you have something important I definitely shouldn't forget, this is the better way.
The module currently has no UI and can only be used by writing macros.
Wait, wtf, why? Because this is a surprisingly difficult thing to write a UI for (there's a lot of overlapping options) and I quite honestly do not have time right now. I think the macro interface is good enough for a first release. I might revisit this decision in the future, but I am not making any promises. If you feel strongly that there should be a UI, this can be communicated to me in the form of pull requests that add one ;)
Create a new macro and change the type to script
. Then enter the following code:
var s = game.modules.get("penllawen-compendium-table-maker").api.getCompendiumSummariser();
await s.makeNewJournalNamed("This is my Journal");
await s.addJournalPageNamed("Gear")
.addInputCompendium("swade-core-rules.swade-equipment")
.writeJournalPage();
await s.addJournalPageNamed("Skills")
.addInputCompendium("swade-core-rules.swade-skills")
.writeJournalPage();
This will compile the SWADE core rules compendium of all Edges and Gear items into a single JournalEntry with two pages, one for each. Obviously, you can change the name of the output journal and pages, and the input Compendium as you please. Note that you need the full "pack name" of the Compendium, in other words swade-core-rules.swade-edges
and not just swade-edges
.
showReport()
at the end is optional but recommended. It'll pop up a little dialog telling you what the module did.
Each time you run this script, it'll make a whole new JournalEntry, which will be in the world (ie. not inside a Compendium.) You can move it afterwards to wherever you like. Used like this, the module will never overwrite any data in any existing Journal.
To do this, just add more addInputCompendium(...)
lines:
var s = game.modules.get("penllawen-compendium-table-maker")
.api.getCompendiumSummariser();
await s.makeNewJournalNamed("This is my Journal for Deadlands");
await s.addJournalPageNamed("Deadlands Edges")
.addInputCompendium("deadlands-core-rules.deadlands-edges")
.addInputCompendium("swade-core-rules.swade-edges")
.writeJournalPage();
You can add as many as you'd like of these. This is a great way to combine the items from core SWADE with the items from a setting like Deadlands.
You might want to change the names of categories in one of two Compendiums you are merging. For example, at the time of writing, the premium SWADE module has Edge categories of "Leadership", "Social", Combat", and so on. But the Deadlands module uses "Leadership Edge", "Social Edge", "Combat Edge" etc. This prevents the module from merging them.
By adding a renamer as shown below to one of the Compendiums, you can make the merge process work again. Here the Deadlands category "Combat Edge" will be renamed to "Combat", and then it will correctly merge with the SWADE Edges in the "Combat" category.
await s.addJournalPageNamed("edges")
.addInputCompendium("swade-core-rules.swade-edges")
.addInputCompendium("deadlands-core-rules.deadlands-edges")
.addCategoryRenamer("Background Edge", "Background")
.addCategoryRenamer("Combat Edge", "Combat")
.addCategoryRenamer("Legendary Edge", "Legendary")
.addCategoryRenamer("Professional Edge", "Professional")
.addCategoryRenamer("Social Edge", "Social")
.addCategoryRenamer("Weird Edge", "Weird ")
.writeJournalPage();
You can also use this to create a Skills list that doesn't break the core skills out into their own table:
await s.addJournalPageNamed("Skills")
.addInputCompendium("swade-core-rules.swade-skills")
.addCategoryRenamer("core", "")
.writeJournalPage();
You may not want every item in the source compendium to make it into your Journal. There are three ways to filter them: on the item's name, on its type ("armor", "weapon", etc), and on its "category" (this is a string on the item's character sheet.) Additionally, each of these can be include-filters (ie. only the matching things are in the Journal) or exclude-filters (the matching thing are left out, and the Journal contains everything else.)
Currently, includeItemsByType
and excludeItemsByType
take the internal SWADE names for item types, which are always in lowercase and always in English. At time of writing, the valid values are: ability
, action
, armour
, consumable
, edge
, gear
, hindrance
, power
, skill
, shield
, and weapon
.
New in v1.4.0: matching between the string you supply and the item is case-insensitive and will ignore accented characters. This should make the filtering less brittle.
Note that you cannot define both an exclude and include filter on the same item characteristic (that doesn't make any sense.) The code will warn you if you try.
The methods to call in your macro are shown here:
var s = game.modules.get("penllawen-compendium-table-maker").api.getCompendiumSummariser();
await s.makeNewJournalNamed("test journal");
await s.addJournalPageNamed("Everything")
.enableDebug()
.addInputCompendium("world.mixed-content-compendium")
.writeJournalPage();
await s.addJournalPageNamed("Just weapons")
.enableDebug()
.addInputCompendium("world.mixed-content-compendium")
.includeItemsByType("weapon")
.writeJournalPage();
await s.addJournalPageNamed("No weapons")
.enableDebug()
.addInputCompendium("world.mixed-content-compendium")
.excludeItemsByType("weapon")
.writeJournalPage();
await s.addJournalPageNamed("Just the backpack")
.enableDebug()
.addInputCompendium("world.mixed-content-compendium")
.includeItemsByName("Backpack")
.writeJournalPage();
await s.addJournalPageNamed("No backpack")
.enableDebug()
.addInputCompendium("world.mixed-content-compendium")
.excludeItemsByName("Backpack")
.writeJournalPage();
await s.addJournalPageNamed("Just lasers")
.enableDebug()
.addInputCompendium("world.mixed-content-compendium")
.includeItemsByCategory("Lasers (Futuristic)")
.writeJournalPage();
await s.addJournalPageNamed("No Lasers")
.enableDebug()
.addInputCompendium("world.mixed-content-compendium")
.excludeItemsByCategory("Lasers (Futuristic)")
.writeJournalPage();
The code below will create a single Journal page with only the weapons from the core SWADE book that are used in a modern setting:
await s.addJournalPageNamed("Modern SWADE weapons")
.enableDebug()
.addInputCompendium("swade-core-rules.swade-personal-weapons")
.excludeItemsByCategory("Blackpowder Weapons")
.excludeItemsByCategory("Melee Weapons, Futuristic")
.excludeItemsByCategory("Melee Weapons, Medieval")
.excludeItemsByCategory("Ranged Weapons, Medieval")
.addInputCompendium("swade-core-rules.swade-modern-firearms")
.excludeItemsByCategory("Lasers (Futuristic)")
.addInputCompendium("swade-core-rules.swade-special-weapons")
.excludeItemsByCategory("Cannons")
.excludeItemsByCategory("Catapults")
.writeJournalPage();
Sometimes you want to say "take all of the items in this compendium except a few specific ones." For example, in the Sprawlrunners setting, quite a few Edges from the core book are not available or replaced by customised versions specific to the setting. You can do this like so:
var s = game.modules.get("penllawen-compendium-table-maker")
.api.getCompendiumSummariser();
await s.makeNewJournalNamed("This is my Journal for Sprawlrunners");
await s.addJournalPageNamed("Sprawlrunners Edges")
.addInputCompendium("sprawl-core-rules.sprawlrunner-edges")
.addInputCompendium("swade-core-rules.swade-edges")
.excludeItemsByName("Arcane Background (Gifted)")
.excludeItemsByName("Arcane Background (Magic)")
.excludeItemsByName("Arcane Background (Miracles)")
.excludeItemsByName("Arcane Background (Psionics)")
.excludeItemsByName("Arcane Background (Weird Science)")
.excludeItemsByName("Aristocrat")
.excludeItemsByName("Rich")
.excludeItemsByName("Filthy Rich")
.excludeItemsByName("Artificer")
.excludeItemsByName("Channeling")
.excludeItemsByName("Concentration")
.excludeItemsByName("Extra Effort")
.excludeItemsByName("Gadgeteer")
.excludeItemsByName("Holy/Unholy Warrior")
.excludeItemsByName("Improved Rapid Recharge")
.excludeItemsByName("Mentalist")
.excludeItemsByName("Power Points")
.excludeItemsByName("Power Surge")
.excludeItemsByName("Rapid Recharge")
.excludeItemsByName("Soul Drain")
.excludeItemsByName("Wizard")
.writeJournalPage();
Some of my houserule compendiums have gear of different types next to each other, for example I have guns and their ammunition in the same compendium. By default, this will produce a single JournalEntry with two tables in it - one for the weapons, one for the ammunition and other gear items. I can change this behaviour by adding a filter on item type:
var s = game.modules.get("penllawen-compendium-table-maker").api.getCompendiumSummariser();
await s.makeNewJournalNamed("This is my Journal for houseruled items");
await s.addJournalPageNamed("Houserule weapons")
.addInputCompendium("penllawen-sprawlrunners-extras.weapons")
.includeItemsByType("weapon")
.writeJournalPage();
await s.addJournalPageNamed("Houserule ammo & gear")
.addInputCompendium("penllawen-sprawlrunners-extras.weapons")
.excludeItemsByType("gear")
.writeJournalPage();
Now I will get one Journal with two pages. One will contain only the weapons, the other only the gear.
var s = game.modules.get("penllawen-compendium-table-maker").api.getCompendiumSummariser();
await s.makeNewJournalNamed("Deadlands stuff");
await s.addJournalPageNamed("Deadlands Edges")
.addInputCompendium("swade-core-rules.swade-edges")
.excludeItemsByName("Arcane Background (Gifted)")
.excludeItemsByName("Arcane Background (Magic)")
.excludeItemsByName("Arcane Background (Miracles)")
.excludeItemsByName("Arcane Background (Psionics)")
.excludeItemsByName("Arcane Background (Weird Science)")
.excludeItemsByName("Soul Drain")
.addInputCompendium("deadlands-core-rules.deadlands-edges")
.addCategoryRenamer("Background Edge", "Background")
.addCategoryRenamer("Combat Edge", "Combat")
.addCategoryRenamer("Legendary Edge", "Legendary")
.addCategoryRenamer("Professional Edge", "Professional")
.addCategoryRenamer("Social Edge", "Social")
.addCategoryRenamer("Weird Edge", "Weird ")
.writeJournalPage();
await s.addJournalPageNamed("Deadlands Hindrances")
.addInputCompendium("deadlands-core-rules.deadlands-hindrances")
.addInputCompendium("swade-core-rules.swade-hindrances")
.writeJournalPage();
s.showReport();
var s = game.modules.get("penllawen-compendium-table-maker").api.getCompendiumSummariser();
await s.makeNewJournalNamed("Sprawlrunners stuff");
await s.addJournalPageNamed("Sprawlrunners Edges")
.addInputCompendium("sprawl-core-rules.sprawlrunner-edges")
.addInputCompendium("swade-core-rules.swade-edges")
.excludeItemsByName("Arcane Background (Gifted)")
.excludeItemsByName("Arcane Background (Magic)")
.excludeItemsByName("Arcane Background (Miracles)")
.excludeItemsByName("Arcane Background (Psionics)")
.excludeItemsByName("Arcane Background (Weird Science)")
.excludeItemsByName("Aristocrat")
.excludeItemsByName("Rich")
.excludeItemsByName("Filthy Rich")
.excludeItemsByName("Artificer")
.excludeItemsByName("Channeling")
.excludeItemsByName("Concentration")
.excludeItemsByName("Extra Effort")
.excludeItemsByName("Gadgeteer")
.excludeItemsByName("Holy/Unholy Warrior")
.excludeItemsByName("Improved Rapid Recharge")
.excludeItemsByName("Mentalist")
.excludeItemsByName("Power Points")
.excludeItemsByName("Power Surge")
.excludeItemsByName("Rapid Recharge")
.excludeItemsByName("Soul Drain")
.excludeItemsByName("Wizard")
.writeJournalPage();
s.showReport();