Skip to content

Commit

Permalink
Merge pull request #13543 from morgdalaine/wilderfeast
Browse files Browse the repository at this point in the history
[New Sheet] Wilderfeast 🍽️
  • Loading branch information
kfroll20 authored Nov 26, 2024
2 parents 20fb8f4 + 5fdd14c commit b92ddb9
Show file tree
Hide file tree
Showing 21 changed files with 3,813 additions and 0 deletions.
7 changes: 7 additions & 0 deletions Wilderfeast/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"plugins": ["@prettier/plugin-pug"],
"pugAttributeSeparator": "as-needed",
"pugSortAttributes": "as-is",
"pugBracketSpacing": false,
"pugPrintWidth": 100
}
33 changes: 33 additions & 0 deletions Wilderfeast/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Welcome to Wilderfeast

![Version](https://img.shields.io/badge/version-1.0.0-blue.svg?cacheSeconds=2592000)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/license/MIT)


An unofficial Roll20 sheet for [Wilderfeast](https://horribleguild.com/us/product-category/roleplaying-games/wilderfeast) Tabletop RPG!

## Install

```sh
# Install all of the npm packages
$ npm install
```

## Usage

> [!WARNING]
> This sheet uses `pug` and SCSS to build the HTML and CSS files respectively. Please do not directly edit the HTML or CSS directly: it will be **wiped away** when the `npm` scripts are ran.
```sh
# Run the development environment
$ npm run dev

# Run final build and linting
$ npm run build
```

<a href='https://ko-fi.com/R5R54NXP1' target='_blank'><img height='20' style='border:0px;height:20px;' src='https://storage.ko-fi.com/cdn/brandasset/v2/kofi_symbol.png' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
[![GitHub](https://img.shields.io/badge/@morgdalaine-whitesmoke?style=social&logo=github)](https://github.com/morgdalaine)
[![GitHub](https://img.shields.io/badge/@morgdalaine-whitesmoke?style=social&logo=discord)](https://discordapp.com/users/186973853011017729)

[^0]: This README was generated with ♥︎ by [readme-md-generator](https://github.com/kefranabg/readme-md-generator)
4 changes: 4 additions & 0 deletions Wilderfeast/assets/d20.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions Wilderfeast/assets/d8.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
45 changes: 45 additions & 0 deletions Wilderfeast/biome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"vcs": {
"enabled": false,
"clientKind": "git",
"useIgnoreFile": false
},
"files": {
"ignoreUnknown": false,
"ignore": []
},
"formatter": {
"enabled": true,
"useEditorconfig": true,
"formatWithErrors": false,
"indentStyle": "space",
"indentWidth": 2,
"lineEnding": "lf",
"lineWidth": 100,
"attributePosition": "auto",
"bracketSpacing": false
},
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true
}
},
"javascript": {
"formatter": {
"arrowParentheses": "always",
"attributePosition": "auto",
"bracketSameLine": false,
"bracketSpacing": true,
"jsxQuoteStyle": "double",
"quoteProperties": "asNeeded",
"quoteStyle": "double",
"semicolons": "always",
"trailingCommas": "es5"
}
}
}
36 changes: 36 additions & 0 deletions Wilderfeast/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"name": "wilderfeast",
"version": "1.0.0",
"author": "morgdalaine",
"scripts": {
"dev": "run-p dev:*",
"build": "run-s lint:pug compile:* i18n lint:biome",

"dev:sass": "npx sass ./src/scss/wilderfeast.scss:wilderfeast.css --watch --no-source-map --no-charset",
"dev:pug": "npx pug3 ./src/pug/wilderfeast.pug -w --out ./ --pretty",

"compile:sass": "npx sass ./src/scss/wilderfeast.scss:wilderfeast.css --no-source-map --no-charset",
"compile:pug": "npx pug3 ./src/pug/wilderfeast.pug --out ./ --pretty",
"compile:css": "npx postcss wilderfeast.css --output wilderfeast.css --use autoprefixer --verbose --no-map",

"i18n": "i18ntool -i wilderfeast.html -a > /dev/null",

"lint:biome": "npx @biomejs/biome check --write ./src",
"lint:pug": "npx prettier --write '**/*.pug' --plugin '@prettier/plugin-pug'"
},
"keywords": ["roll20"],
"license": "MIT",
"devDependencies": {
"@anduh/pug-cli": "^1.0.0-alpha8",
"@biomejs/biome": "1.9.4",
"@prettier/plugin-pug": "^3.2.0",
"autoprefixer": "^10.4.20",
"npm-run-all": "^4.1.5",
"postcss": "^8.4.49",
"postcss-cli": "^11.0.0",
"prettier": "^3.3.3",
"pug": "^3.0.3",
"sass": "^1.81.0",
"typescript": "^5.6.3"
}
}
9 changes: 9 additions & 0 deletions Wilderfeast/sheet.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"html": "wilderfeast.html",
"css": "wilderfeast.css",
"authors": "morgdalaine",
"roll20userid": "61327",
"preview": "wilderfeast.png",
"instructions": "The Unofficial Roll20 Wilderfeast TTRPG character sheet",
"useroptions": []
}
36 changes: 36 additions & 0 deletions Wilderfeast/src/js/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
const STYLES = ["mighty", "precise", "swift", "tricky"];
const SKILLS = [
"assurance",
"display",
"shot",
"call",
"grab",
"strike",
"craft",
"hoard",
"study",
"cure",
"search",
"traversal",
];

const CONDITIONS = [
{ label: "Burned", name: "burned" },
{ label: "Caught", name: "caught" },
{ label: "Confused", name: "confused", min: 1 },
{ label: "Discordant", name: "discordant" },
{ label: "Expanded", name: "expanded" },
{ label: "Exposed", name: "exposed" },
{ label: "Fatigued", name: "fatigued", min: 1 },
{ label: "Frightened", name: "frightened", min: 1 },
{ label: "Invigorated", name: "invigorated", min: 1 },
{ label: "Hidden", name: "hidden" },
{ label: "Poisoned", name: "poisoned", min: 1 },
{ label: "Rehabilitating", name: "rehabilitating", min: 1, max: 6 },
{ label: "Rested", name: "rested", min: 1 },
{ label: "Stunned", name: "stunned", min: 1 },
{ label: "Wounded", name: "wounded", min: 1, max: 3 },
];
const CONDITIONS_REQUEST = CONDITIONS.flatMap((c) => [c.name, `${c.name}_level`]);

const MAX_FIELDS = ["hp", "tool_durability", "harmony"];
82 changes: 82 additions & 0 deletions Wilderfeast/src/js/dice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
on("clicked:focus_up", async (eventInfo) => {
rollAction();
});
on("clicked:go_wild", async (eventInfo) => {
rollAction(true);
});

/**
*
* @param {string} template name of rolltemplate to use
* @param {object} properties key value pairs
* @param {function} callback startRoll callback function; should include `finishRoll()`
*/
const makeRoll = async (template, properties, callback) => {
const rollstring = createRollString(template, properties);
await startRoll(rollstring, callback);
};

/**
* Create roll string including whisper, template, and roll properties
* @param {string} template name of rolltemplate to use
* @param {object} properties key value pairs
* @returns finished roll string
*/
const createRollString = (template, properties) => {
const props = Object.entries(properties)
.map(([key, val]) => `{{${key}=${val}}}`)
.join("");

// return `@{wtype}&{template:${template}}${props}`;
return `&{template:${template}}${props}`;
};

const rollAction = async (wild = false) => {
getAttrs(
["style", "skill", "advantage", ...STYLES, ...SKILLS, ...CONDITIONS_REQUEST],
(attributes) => {
const styleName = attributes.style;
const skillName = attributes.skill;
const style = Number(attributes[styleName]) ?? 0;
const skill = Number(attributes[skillName]) ?? 0;

console.debug(attributes);
const properties = {};

const dic = {};
dic.action = getTranslationByKey("action") || "Action";
dic.frightened = getTranslationByKey("frightened") || "Frightened";

properties.character_name = "@{character_name}";
properties.style = `^{${styleName}}`;
properties.skill = `^{${skillName}} (+${skill})`;

const action_is = wild ? "wild" : "focus";
properties[action_is] = action_is;
properties.action_is = action_is;

properties.question = "[[?{Circumstances|Normal,0|Advantage,1|Disadvantage,-1}]]";

const dice = style - (wild ? 1 : 0);
for (const key of Array.from(Array(dice).keys(), (k) => k + 1)) {
properties[`roll_style${key}`] = "[[1d6]]";
}

const frightenedLevel =
attributes.frightened === "on" ? Number(attributes.frightened_level) : 0;
const frightenedMod =
frightenedLevel > 0 ? `+ ${-1 * frightenedLevel}[${dic.frightened}]` : "";
properties.roll_action = `[[1d${wild ? 20 : 8}[${dic.action}] ${frightenedMod}]]`;

makeRoll("action", properties, ({ rollId, results }) => {
finishRoll(rollId, results);

// const answer = Number(results.question.result);
// const circumstance = answer > 0 ? "advantage" : answer < 0 ? "disadvantage" : "";
// finishRoll(rollId, {
// [circumstance]: true,
// });
});
}
);
};
35 changes: 35 additions & 0 deletions Wilderfeast/src/js/eventhandlers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Handle conditions that affect other rolls
for (const condition of CONDITIONS) {
on(`change:${condition.name} change:${condition.name}_level`, (eventInfo) => {
getAttrs(CONDITIONS_REQUEST, (attributes) => {
const state = attributes[condition.name];
const level = state === "on" ? Number(attributes[`${condition.name}_level`]) : 0;

switch (condition.name) {
case "fatigued":
setAttrs({ hp_mod: -1 * level }, { silent: true });
break;

default:
break;
}
});
});
}

// Handle attributes with an underscore_max attribute
for (const field of MAX_FIELDS) {
on(`change:${field}`, (eventInfo) => {
if (eventInfo.sourceType !== "player") return;

getAttrs([field, `${field}_max`, `${field}_mod`], (attributes) => {
const current = Number(attributes[field]);
const max = Number(attributes[`${field}_max`]);
const mod = Number(attributes[`${field}_mod`]) || 0;

if (current > max + mod) {
setAttrs({ [field]: max + mod }, { silent: true });
}
});
});
}
90 changes: 90 additions & 0 deletions Wilderfeast/src/pug/rolltemplate.pug
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
- const DICE = Array.from(Array(10).keys(), (key) => `roll_style${key + 1}`);

mixin tags(array)
each tag in array
if (tag[0] === "^")
| {{#{tag}}}
else
| {{##{tag}}}
if block
block
each tag in array.reverse()
if (tag[0] === "^")
- tag = tag.slice(1);
| {{/#{tag}}}
else
| {{/#{tag}}}

mixin rollFunctions(array)
each tag in array
| {{##{tag}}}
if block
block
each tag in array.reverse()
| {{/#{tag}}}

mixin displayDie(die)
+rollFunctions([`rollBetween() ${die} 1 1`])
span.sheet-wf-style__face-1= `{{${die}}}`
+rollFunctions([`rollBetween() ${die} 2 2`])
span.sheet-wf-style__face-2= `{{${die}}}`
+rollFunctions([`rollBetween() ${die} 3 3`])
span.sheet-wf-style__face-3= `{{${die}}}`
+rollFunctions([`rollBetween() ${die} 4 4`])
span.sheet-wf-style__face-4= `{{${die}}}`
+rollFunctions([`rollBetween() ${die} 5 5`])
span.sheet-wf-style__face-5= `{{${die}}}`
+rollFunctions([`rollBetween() ${die} 6 20`])
span.sheet-wf-style__face-6= `{{${die}}}`

rolltemplate.sheet-rolltemplate-action
.sheet-wf-wrapper
.sheet-wf-header
+tags(["character_name"])
.sheet-wf-character-name
span {{character_name}}
+tags(["wild"])
.sheet-wf-go-wild
span(data-i18n="goes_wild") Goes&#10;Wild
+tags(["focus"])
.sheet-wf-focus-up
span(data-i18n="focuses_up") Focuses&#10;Up
.sheet-wf-circumstance
+rollFunctions(["rollBetween() question 1 1"])
span(data-i18n="advantage") Advantage!
+rollFunctions(["rollBetween() question -1 -1"])
span(data-i18n="disadvantage") Disadvantage!

.sheet-wf-style-and-skill
span.sheet-wf-header--style {{style}}
| &nbsp;
span.sheet-wf-header--skill {{skill}}

.sheet-wf-dice-tray
.sheet-wf-style
+rollFunctions(["rollBetween() question 1 1"])
.sheet-wf-style__roll--advantage
each die in DICE
+tags([die])
+displayDie(die)
+rollFunctions(["rollBetween() question 0 0"])
.sheet-wf-style__roll
each die in DICE
+tags([die])
+displayDie(die)
+rollFunctions(["rollBetween() question -1 -1"])
.sheet-wf-style__roll--disadvantage
each die in DICE
+tags([die])
+displayDie(die)

.sheet-wf-action(class="sheet-wf-action--{{action_is}}")
+rollFunctions(["rollBetween() roll_action 1 4"])
span.sheet-wf-action__roll--partial {{roll_action}}
span.sheet-wf-action__result(data-i18n="success_partial") Partial Success
+rollFunctions(["rollBetween() roll_action 5 7"])
span.sheet-wf-action__roll {{roll_action}}
span.sheet-wf-action__result(data-i18n="success_standard") Standard Success
+rollFunctions(["rollBetween() roll_action 8 20"])
span.sheet-wf-action__roll--critical {{roll_action}}
span.sheet-wf-action__result(data-i18n="success_critical") Critical Success
Loading

0 comments on commit b92ddb9

Please sign in to comment.