Ars Magica 5 sheet
This folder contains the source code for the Roll20 VTT sheet for the Ars Magica 5th Edition, system.
The sheet was originally made by Coal Powered Puppet. It is currently maintained by Medieve and Riernar.
Getting help & providing feedback
If you have question, need help or would like to provide feedback, you can:
-
Ask on the unofficial Ars Magica 5th Discord in the
#roll20-vttchannel. Tag@Riernar. This is ideal for quick questions. -
Open an issue in Roll20's sheet repository. Include
[Ars Magica 5th]in your title and tag@Riernar. -
Open an issue in Riernar's own repository where I develop the sheet. This is where I schedule up-coming features, so be sure to check here if you have a feature request: maybe it's already in the work !
Contributing
See Roll20's own guide on how to contribute to sheets in general. This section details specific of this sheet.
If you have a feature request, please look in Riernar's own repository where feature request are recorded (so as not to bloat Roll20's repo with issues).
When making a PR directly to the Roll20's repo, please tag @Riernar so that I can keep the development repo above in sync.
Tools
This repo uses the following tools:
- PUG is a template engine for HTML, which makes building the sheet much easier, by having reusable code
- SCSS is similarly a way to write CSS much more easily
- k-scaffold is a set of PUG mixins and SCSS tailored toward Roll20's character sheet, made by Scott Casey. It makes building sheets much easier by provided standard element and logic used in sheets.
- node.js is a javascript runtime. We use it with
npmto handle the javascript package needed to build the sheet from the.pug,.scss,.mdand.jssource files. In particular, the modules:pugis used to compile the source.pugfilessassis used to compile the source.scssfilesmarkdown-itis used to render the markdown.mdfiles inside the sheetNote
We cannot use prepros, because we need to pass additional javascript values to pug during compilation, in particular
node.js'srequirefunction.
Development environment
- You'll need an installation of
npm. We recommend usingnvm(Node Version Manager) to managenode.jsfor you. It lets you have multiple versions of node.js at the same time - Once you have node and npm, run
npm installin the directory to install the packages described by thepackage.jsonfile (this file is generated by npm when you use it).
Building the sheet
You can use the
npm run start
command to tell K-Scaffold to monitor all the files in the source/ repository and keep
the built sheet up-to-date. This works really well with Scott Casey's
Roll20 API and Sheet Autouploader
Chrome(ium) extension that will keep your sandbox up-to-date with the latest generated files.
Alternatively, yo generate the sheet once, run
npm run build
in a terminal.
File organization and naming scheme
All the source files are in source/. The compiled files will be produced in the root folder.
All PUG and SCSS files not starting with a leading underscore _ will be compiled by K-Scaffold.
Legacy code
This sheet is currently being ported from raw HTML/CSS with a python layer, to PUG/SCSS, k-scaffold
and javascript.
The last generated version of the sheet using the old tools is found in source/legacy/, splitted
and formatted appropriately so that it may be injected in PUG. This let us update parts of the sheet
in an incremental fashion.
The original source files for this generation are in source/legacy/source for reference only.
New PUG code
All the source files are in source/. There are 4 kind of source files:
.pugfiles are for generating HTML with PUG.scssfiles are for generating CSS with Sass.jsfiles are included in pug to produce helpers, and also contain sheetworkers ( javascript that ends up as-is in the sheet and will be run inside the VTT)..mdfiles are Markdown files wich are rendered to HTML by PUG. They are used to write simple HTML, and also have files that can be viewed directly in github. Examples include the sheet documentation and the changelog.
For javascript files, there are actually two javascript runtimes involved in that sheet:
- At build time, that is when the
node.jspackagepugis rendering the.pugfiles to HTML. PUG is written in javascript and allows javascript code inside the.pugfiles to run to generate the sheet. This makes it very powerful. Javascript files that are used at sheet generation time end in.pug.jsto make it clear when the javascript code is used. - At game time, when the sheet is loaded and running inside Roll20. This is typically known
as sheetworkers: javascript that runs inside the VTT.
Javascritp files which are included in the sheet to be sheetworker are named
.sheet.jsto make it clear when the javascript code is used.
Advanced techniques used in the sheet
Importing javascript into PUG runtime
When compiling PUG into HTML, we pass custom values into the PUG runtime with generate.js.
In particular, we pass node's require function, allowing us to load node packages or
our own .js files into the PUG runtime.
Deferred attribute lookup
Note
The technique below pre-dates Custom Roll Parsing and could be replaced by CRP.
The sheet uses deferred attribute lookup for spells and abilities. This is simply a clever
way of writing roll20's rolls, so that you fetches the value of an attribute named according
to another attribute value. That is, if your spell's art is Creo, you store the value 'creo'
in the attribute linked to the spell (so that you can use the name, e.g. for inline labels),
but you're able to lookup the Creo_Score attribute for the roll.
The Roll20 dice engine accepts up to 99-levels of nested attributes lookup (using the
@{attr_name} syntax). If you use adjacent attributes lookup that, when resolve, yields a
new attribute lookup, the next pass will resolve that attribute lookup normally. This is exactly
like having an attribute lookup inside another, but the inner lookup is spread into several
attributes. The important things is that all parts are resolved during the same pass.
Example
An example and a table makes things easier to understand. The "system" attributes used to build the query have the same name as they do in the sheet. We use "NAME" as a placeholder for the character's name.
Initial roll formula:
@{sys_at}@{character_name}@{sys_pipe}@{spell_tech_name}_Score@{sys_rbk}First Pass
Input:
@{sys_at}@{character_name}@{sys_pipe}@{spell_tech_name}_Score@{sys_rbk}
@{sys_at} @{character_name} @{sys_pipe} @{spell_tech_name} _Score @{sys_rbk} VALUE @{ NAME | Creo _Score } Output:
@{NAME|Creo_Score}Second Pass
Input:
@{NAME|Creo_Score}Output: the character's score in Creo
This makes it possible to use inline labels that shows the name of the attribute that was looked up, e.g.
@{sys_at}@{character_name}@{sys_pipe}@{spell_tech_name}_Score@{sys_rbk} [@{spell_tech_name}]
Assuming you have a Creo score of 3, this yields 3 [Creo], which tells you where that +3
comes from. The sheet pushes this further, as the inline labels use the same deferred attribute
lookup technique, to translate the labels to you local langages: a sheet worker creates
attributes ending in _i18n (short for internationalization) -- such as Creo_i18n --
that contain the local translation of the word. It then uses deferred attribute lookup to
translate the inline label.
While this is not very useful for Arts since many langage just use the Latin word, it is indeed useful for translating characteristics names in ability rolls, or words & gestures in spell rolls etc.