Files

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-vtt channel. 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 npm to handle the javascript package needed to build the sheet from the .pug, .scss, .md and .js source files. In particular, the modules:
    • pug is used to compile the source .pug files
    • sass is used to compile the source .scss files
    • markdown-it is used to render the markdown .md files inside the sheet

      Note

      We cannot use prepros, because we need to pass additional javascript values to pug during compilation, in particular node.js's require function.

Development environment

  • You'll need an installation of npm. We recommend using nvm (Node Version Manager) to manage node.js for you. It lets you have multiple versions of node.js at the same time
  • Once you have node and npm, run npm install in the directory to install the packages described by the package.json file (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:

  • .pug files are for generating HTML with PUG
  • .scss files are for generating CSS with Sass
  • .js files 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).
  • .md files 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.js package pug is rendering the .pug files to HTML. PUG is written in javascript and allows javascript code inside the .pug files to run to generate the sheet. This makes it very powerful. Javascript files that are used at sheet generation time end in .pug.js to 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.js to 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.