From fccfe5d5439ffdb61040ff0b36955803cf5696d7 Mon Sep 17 00:00:00 2001
From: Matt Smith
Date: Mon, 12 Jan 2026 21:06:52 -0600
Subject: [PATCH 01/11] First pass at crucibles
- Added crucible schema to talents
- Added logic to roll crucibles
- Added logic to render crucibles to chat
- Added vue templates for editing crucibles
---
src/module/data/item-talent.mjs | 47 +++++++++++++++-
src/module/helpers/schema.mjs | 32 ++++++++---
src/module/sheets/item-sheet-vue.mjs | 22 ++++++--
src/styles/components/_crucible.scss | 31 +++++++++++
src/styles/global/_window.scss | 1 +
src/styles/grimwild.scss | 1 +
src/vue/components/index.mjs | 1 +
src/vue/components/item/ItemAttributes.vue | 4 +-
src/vue/components/item/ItemCrucible.vue | 62 ++++++++++++++++++++++
9 files changed, 188 insertions(+), 13 deletions(-)
create mode 100644 src/styles/components/_crucible.scss
create mode 100644 src/vue/components/item/ItemCrucible.vue
diff --git a/src/module/data/item-talent.mjs b/src/module/data/item-talent.mjs
index cef854e..83a9052 100644
--- a/src/module/data/item-talent.mjs
+++ b/src/module/data/item-talent.mjs
@@ -1,4 +1,4 @@
-import { DicePoolField } from "../helpers/schema.mjs";
+import { DicePoolField, CrucibleTableField } from "../helpers/schema.mjs";
import GrimwildItemBase from "./base-item.mjs";
export default class GrimwildTalent extends GrimwildItemBase {
@@ -51,9 +51,54 @@ export default class GrimwildTalent extends GrimwildItemBase {
})
}));
+ // Crucible.
+ schema.crucible = new CrucibleTableField();
+
return schema;
}
+ async rollCrucible(options = {}) {
+ const row = new Roll('d6');
+ const col = new Roll('d6');
+
+ await row.roll();
+ await col.roll();
+
+ const result = [
+ this.crucible.table[row.result][col.result],
+ this.crucible.table[col.result][row.result],
+ ];
+
+ if (options?.toMessage) {
+ ChatMessage.create({
+ speaker: ChatMessage.getSpeaker({ actor: this.parent }),
+ content: `
+
+
+
${this.crucible.name ?? 'Crucible'}
+
+ ${result[0]}
+ ${result[1]}
+
+
+
+
+ `,
+ })
+ }
+
+ return result;
+ }
+
/**
* Migrate source data from prior format to the new specification.
*
diff --git a/src/module/helpers/schema.mjs b/src/module/helpers/schema.mjs
index 9a8c815..ccd3756 100644
--- a/src/module/helpers/schema.mjs
+++ b/src/module/helpers/schema.mjs
@@ -1,4 +1,3 @@
-
const fields = foundry.data.fields;
const requiredInteger = { required: true, nullable: false, integer: true };
const requiredString = { required: true, blank: true };
@@ -22,17 +21,36 @@ export class DicePoolField extends fields.SchemaField {
export class CrucibleTableField extends fields.SchemaField {
constructor(options, context = {}) {
+
+ /* ------------------------------------------------- */
+ // Build our table structure with nested schema fields.
+ /* ------------------------------------------------- */
+ // Build the outer columns.
+ const cols = {};
+ const d66 = Array.fromRange(6, 1);
+ d66.forEach((col) => {
+ // Build the inner rows.
+ const rows = {};
+ d66.forEach((row) => {
+ // Inner string for the actual value.
+ rows[row] = new fields.StringField(requiredString);
+ });
+ // Inner schema for rows.
+ cols[col] = new fields.SchemaField(rows);
+ });
+ // Outer schema for cols.
+ const tableSchema = new fields.SchemaField(cols);
+
+ /* ------------------------------------------------- */
+
+ // Prepare the table fields for the data model.
const tableFields = {
// Table name.
name: new fields.StringField(requiredString),
// Table roll instructions.
instructions: new fields.StringField(optionalString),
- // Table results.
- table: new fields.ArrayField( // Column.
- new fields.ArrayField( // Row.
- new fields.StringField(requiredString) // Value.
- )
- )
+ // Table results. Outer schema is columns, inner schema is rows.
+ table: tableSchema,
};
super(tableFields, options, context);
diff --git a/src/module/sheets/item-sheet-vue.mjs b/src/module/sheets/item-sheet-vue.mjs
index 2db4080..6a293c0 100644
--- a/src/module/sheets/item-sheet-vue.mjs
+++ b/src/module/sheets/item-sheet-vue.mjs
@@ -23,7 +23,7 @@ export class GrimwildItemSheetVue extends VueRenderingMixin(GrimwildBaseVueItemS
viewPermission: DOCUMENT_OWNERSHIP_LEVELS.LIMITED,
editPermission: DOCUMENT_OWNERSHIP_LEVELS.OWNER,
position: {
- width: 478
+ width: 600,
// height: 720,
},
window: {
@@ -40,7 +40,8 @@ export class GrimwildItemSheetVue extends VueRenderingMixin(GrimwildBaseVueItemS
deleteTracker: this._deleteTracker,
createArrayEntry: this._createArrayEntry,
deleteArrayEntry: this._deleteArrayEntry,
- rollPool: this._rollPool
+ rollPool: this._rollPool,
+ rollCrucible: this._rollCrucible,
},
// Custom property that's merged into `this.options`
dragDrop: [{ dragSelector: "[data-drag]", dropSelector: null }],
@@ -346,8 +347,8 @@ export class GrimwildItemSheetVue extends VueRenderingMixin(GrimwildBaseVueItemS
}
/**
- * Handle rolling pools on the character sheet.
- * @todo abstract this to the actor itself.
+ * Handle rolling pools on the item sheet.
+ * @todo abstract this to the item itself.
*
* @param {PointerEvent} event The originating click event
* @param {HTMLElement} target The capturing HTML element which defined a [data-action]
@@ -411,4 +412,17 @@ export class GrimwildItemSheetVue extends VueRenderingMixin(GrimwildBaseVueItemS
}
}
}
+
+ /**
+ * Handle rolling crucibles on the item sheet.
+ * @todo abstract this to the item itself.
+ *
+ * @param {PointerEvent} event The originating click event
+ * @param {HTMLElement} target The capturing HTML element which defined a [data-action]
+ * @private
+ */
+ static async _rollCrucible(event, target) {
+ event.preventDefault();
+ const result = await this.document.system.rollCrucible({toMessage: true});
+ }
}
diff --git a/src/styles/components/_crucible.scss b/src/styles/components/_crucible.scss
new file mode 100644
index 0000000..0aabc6a
--- /dev/null
+++ b/src/styles/components/_crucible.scss
@@ -0,0 +1,31 @@
+.crucible {
+ .form-group {
+ max-width: 100%;
+ }
+
+ .responsive-table {
+ // Arbitrary number, it will be expanded by flexbox.
+ width: 300px;
+ }
+
+ table {
+ margin: 0;
+ display: block;
+ overflow-x: auto;
+ white-space: nowrap;
+
+ tbody {
+ display: table;
+ width: 100%;
+ }
+
+ tr:nth-child(even) {
+ background-color: #ffffff0a;
+ }
+
+ td {
+ padding: 4px;
+ border: 1px dashed #ffffff33;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/styles/global/_window.scss b/src/styles/global/_window.scss
index fe8c4bc..13a8f96 100644
--- a/src/styles/global/_window.scss
+++ b/src/styles/global/_window.scss
@@ -37,6 +37,7 @@
.tab {
flex: 1;
overflow-y: auto;
+ overflow-x: hidden;
}
}
diff --git a/src/styles/grimwild.scss b/src/styles/grimwild.scss
index ceac97f..2b60af0 100644
--- a/src/styles/grimwild.scss
+++ b/src/styles/grimwild.scss
@@ -20,6 +20,7 @@
@import 'components/forms';
@import 'components/items';
@import 'components/effects';
+ @import 'components/crucible';
@import 'components/stats';
@import 'components/backgrounds';
@import 'components/character';
diff --git a/src/vue/components/index.mjs b/src/vue/components/index.mjs
index 108ecd1..577fd23 100644
--- a/src/vue/components/index.mjs
+++ b/src/vue/components/index.mjs
@@ -16,6 +16,7 @@ export { default as MonsterDesires } from "@/components/actor/monster/MonsterDes
export { default as ItemDescription } from "@/components/item/ItemDescription.vue";
export { default as ItemHeader } from "@/components/item/ItemHeader.vue";
export { default as ItemAttributes } from "@/components/item/ItemAttributes.vue";
+export { default as ItemCrucible } from "@/components/item/ItemCrucible.vue";
export { default as TalentTrackers } from "@/components/item/talent/TalentTrackers.vue";
export { default as ArcanaDetails } from "@/components/item/arcana/ArcanaDetails.vue";
export { default as ChallengeTraitsMoves } from "@/components/item/challenge/ChallengeTraitsMoves.vue";
diff --git a/src/vue/components/item/ItemAttributes.vue b/src/vue/components/item/ItemAttributes.vue
index 83024e1..1f2de26 100644
--- a/src/vue/components/item/ItemAttributes.vue
+++ b/src/vue/components/item/ItemAttributes.vue
@@ -1,4 +1,5 @@
+
@@ -7,7 +8,8 @@
import { inject } from 'vue';
import {
TalentTrackers,
- ChallengeTraitsMoves
+ ChallengeTraitsMoves,
+ ItemCrucible,
} from '@/components';
const props = defineProps(['context']);
const actor = inject('rawDocument');
diff --git a/src/vue/components/item/ItemCrucible.vue b/src/vue/components/item/ItemCrucible.vue
new file mode 100644
index 0000000..6410aae
--- /dev/null
+++ b/src/vue/components/item/ItemCrucible.vue
@@ -0,0 +1,62 @@
+
+
+ Crucible
+
+
+
+
+
\ No newline at end of file
From 93d471bdb47e9a0f2429f0b4d944b4710f68e971 Mon Sep 17 00:00:00 2001
From: Matt Smith
Date: Fri, 16 Jan 2026 17:19:01 -0600
Subject: [PATCH 02/11] WIP for an actual crucible roll class
---
src/module/data/item-talent.mjs | 1 +
src/module/dice/_module.mjs | 1 +
src/module/dice/crucible-rolls.mjs | 33 ++++++++++++++++++++++++++++
src/module/grimwild.mjs | 3 ++-
src/templates/chat/roll-crucible.hbs | 21 ++++++++++++++++++
5 files changed, 58 insertions(+), 1 deletion(-)
create mode 100644 src/module/dice/crucible-rolls.mjs
create mode 100644 src/templates/chat/roll-crucible.hbs
diff --git a/src/module/data/item-talent.mjs b/src/module/data/item-talent.mjs
index 83a9052..d4b31ff 100644
--- a/src/module/data/item-talent.mjs
+++ b/src/module/data/item-talent.mjs
@@ -58,6 +58,7 @@ export default class GrimwildTalent extends GrimwildItemBase {
}
async rollCrucible(options = {}) {
+ // @TODO use the GrimwildCrucibleRoll class.
const row = new Roll('d6');
const col = new Roll('d6');
diff --git a/src/module/dice/_module.mjs b/src/module/dice/_module.mjs
index 7c8afbb..a1423e6 100644
--- a/src/module/dice/_module.mjs
+++ b/src/module/dice/_module.mjs
@@ -1,2 +1,3 @@
export { default as GrimwildRoll } from "./rolls.mjs";
+export { default as GrimwildCrucibleRoll } from "./crucible-rolls.mjs";
export { default as GrimwildDiePoolRoll } from "./die-pools.mjs";
diff --git a/src/module/dice/crucible-rolls.mjs b/src/module/dice/crucible-rolls.mjs
new file mode 100644
index 0000000..d4a9cb9
--- /dev/null
+++ b/src/module/dice/crucible-rolls.mjs
@@ -0,0 +1,33 @@
+// @TODO make this actually work.
+export default class GrimwildCrucibleRoll extends Roll {
+ static CHAT_TEMPLATE = "systems/grimwild/templates/chat/roll-crucible.hbs";
+
+ constructor(formula, data, options) {
+ super(formula, data, options);
+ if (game.dice3d && game.settings.get("grimwild", "diceSoNiceOverride")) {
+ if (!this.options.appearance) this.options.appearance = {};
+ this.options.appearance.system = "grimwild";
+ this.options.appearance.colorset = "grimwild-dark";
+ }
+ }
+
+ async render({ flavor, template=this.constructor.CHAT_TEMPLATE, isPrivate=false }={}) {
+ if (!this._evaluated) await this.evaluate();
+
+ const chatData = {
+ formula: isPrivate ? "???" : this._formula,
+ flavor: isPrivate ? null : flavor ?? this.options.flavor,
+ user: game.user.id,
+ tooltip: isPrivate ? "" : await this.getTooltip(),
+ stat: this.options.stat,
+ dice: this.dice[0].results,
+ crucible: {
+ 0: this.options.crucible.table[this.dice[0].results[0]],
+ 1: this.options.crucible.table[this.dice[0].results[1]],
+ },
+ isPrivate: isPrivate
+ };
+
+ return foundry.applications.handlebars.renderTemplate(template, chatData);
+ }
+}
diff --git a/src/module/grimwild.mjs b/src/module/grimwild.mjs
index 103445e..0da867d 100644
--- a/src/module/grimwild.mjs
+++ b/src/module/grimwild.mjs
@@ -45,7 +45,8 @@ globalThis.grimwild = {
},
models,
roll: dice.GrimwildRoll,
- diePools: dice.GrimwildDiePoolRoll
+ rollCrucible: dice.GrimwildCrucibleRoll,
+ diePools: dice.GrimwildDiePoolRoll,
};
Hooks.once("init", function () {
diff --git a/src/templates/chat/roll-crucible.hbs b/src/templates/chat/roll-crucible.hbs
new file mode 100644
index 0000000..2b42037
--- /dev/null
+++ b/src/templates/chat/roll-crucible.hbs
@@ -0,0 +1,21 @@
+{{#unless isPrivate}}
+
+
+
{{ name }}
+
+ {{ crucible.0 }}
+ {{ crucible.1 }}
+
+
+
+
+{{/unless}}
\ No newline at end of file
From 310eed27de16555c8292b2f4536e5e96abefd7d9 Mon Sep 17 00:00:00 2001
From: Matt Smith
Date: Fri, 16 Jan 2026 17:44:30 -0600
Subject: [PATCH 03/11] Crucible progress
---
src/module/data/item-talent.mjs | 7 +++++++
src/module/dice/crucible-rolls.mjs | 2 ++
2 files changed, 9 insertions(+)
diff --git a/src/module/data/item-talent.mjs b/src/module/data/item-talent.mjs
index d4b31ff..bd820a1 100644
--- a/src/module/data/item-talent.mjs
+++ b/src/module/data/item-talent.mjs
@@ -59,6 +59,13 @@ export default class GrimwildTalent extends GrimwildItemBase {
async rollCrucible(options = {}) {
// @TODO use the GrimwildCrucibleRoll class.
+ // const r = new grimwild.rollCrucible('{2d6}', {}, {crucible: this.crucible});
+ // await r.roll();
+ // console.log('crucible', r);
+ // if (options.toMessage) {
+ // r.toMessage();
+ // }
+
const row = new Roll('d6');
const col = new Roll('d6');
diff --git a/src/module/dice/crucible-rolls.mjs b/src/module/dice/crucible-rolls.mjs
index d4a9cb9..1ff9e33 100644
--- a/src/module/dice/crucible-rolls.mjs
+++ b/src/module/dice/crucible-rolls.mjs
@@ -4,6 +4,7 @@ export default class GrimwildCrucibleRoll extends Roll {
constructor(formula, data, options) {
super(formula, data, options);
+ console.log('crucible', this);
if (game.dice3d && game.settings.get("grimwild", "diceSoNiceOverride")) {
if (!this.options.appearance) this.options.appearance = {};
this.options.appearance.system = "grimwild";
@@ -12,6 +13,7 @@ export default class GrimwildCrucibleRoll extends Roll {
}
async render({ flavor, template=this.constructor.CHAT_TEMPLATE, isPrivate=false }={}) {
+ console.log('crucible', this);
if (!this._evaluated) await this.evaluate();
const chatData = {
From b3465bcea2cd3236b3e7584c12a1876dc2fc9105 Mon Sep 17 00:00:00 2001
From: Matt Smith
Date: Sat, 17 Jan 2026 10:08:49 -0600
Subject: [PATCH 04/11] Refactor talent crucible rolls
---
src/module/data/item-talent.mjs | 48 +++-------------------------
src/module/dice/crucible-rolls.mjs | 14 +++++---
src/module/grimwild.mjs | 2 ++
src/module/helpers/utils.js | 4 ++-
src/templates/chat/roll-crucible.hbs | 10 +++---
5 files changed, 24 insertions(+), 54 deletions(-)
diff --git a/src/module/data/item-talent.mjs b/src/module/data/item-talent.mjs
index bd820a1..8e5c9c6 100644
--- a/src/module/data/item-talent.mjs
+++ b/src/module/data/item-talent.mjs
@@ -58,50 +58,10 @@ export default class GrimwildTalent extends GrimwildItemBase {
}
async rollCrucible(options = {}) {
- // @TODO use the GrimwildCrucibleRoll class.
- // const r = new grimwild.rollCrucible('{2d6}', {}, {crucible: this.crucible});
- // await r.roll();
- // console.log('crucible', r);
- // if (options.toMessage) {
- // r.toMessage();
- // }
-
- const row = new Roll('d6');
- const col = new Roll('d6');
-
- await row.roll();
- await col.roll();
-
- const result = [
- this.crucible.table[row.result][col.result],
- this.crucible.table[col.result][row.result],
- ];
-
- if (options?.toMessage) {
- ChatMessage.create({
- speaker: ChatMessage.getSpeaker({ actor: this.parent }),
- content: `
-
-
-
${this.crucible.name ?? 'Crucible'}
-
- ${result[0]}
- ${result[1]}
-
-
-
-
- `,
- })
+ const result = new grimwild.rollCrucible('{2d6}', {}, {crucible: this.crucible});
+ await result.roll();
+ if (options.toMessage) {
+ result.toMessage();
}
return result;
diff --git a/src/module/dice/crucible-rolls.mjs b/src/module/dice/crucible-rolls.mjs
index 1ff9e33..adf0b9c 100644
--- a/src/module/dice/crucible-rolls.mjs
+++ b/src/module/dice/crucible-rolls.mjs
@@ -4,17 +4,20 @@ export default class GrimwildCrucibleRoll extends Roll {
constructor(formula, data, options) {
super(formula, data, options);
- console.log('crucible', this);
if (game.dice3d && game.settings.get("grimwild", "diceSoNiceOverride")) {
if (!this.options.appearance) this.options.appearance = {};
this.options.appearance.system = "grimwild";
this.options.appearance.colorset = "grimwild-dark";
}
+
+ if (!this.options.crucible) {
+ throw new Error(`A crucible object must be supplied in options.crucible for this roll.`);
+ }
}
async render({ flavor, template=this.constructor.CHAT_TEMPLATE, isPrivate=false }={}) {
- console.log('crucible', this);
if (!this._evaluated) await this.evaluate();
+ const dice = this.dice[0].results;
const chatData = {
formula: isPrivate ? "???" : this._formula,
@@ -22,10 +25,11 @@ export default class GrimwildCrucibleRoll extends Roll {
user: game.user.id,
tooltip: isPrivate ? "" : await this.getTooltip(),
stat: this.options.stat,
- dice: this.dice[0].results,
+ dice: dice,
+ name: this.options.crucible?.name ?? 'Crucible',
crucible: {
- 0: this.options.crucible.table[this.dice[0].results[0]],
- 1: this.options.crucible.table[this.dice[0].results[1]],
+ 0: this.options.crucible.table[dice[0].result][dice[1].result],
+ 1: this.options.crucible.table[dice[1].result][dice[0].result],
},
isPrivate: isPrivate
};
diff --git a/src/module/grimwild.mjs b/src/module/grimwild.mjs
index 0da867d..4272171 100644
--- a/src/module/grimwild.mjs
+++ b/src/module/grimwild.mjs
@@ -67,6 +67,8 @@ Hooks.once("init", function () {
CONFIG.Dice.rolls.push(dice.GrimwildRoll);
CONFIG.Dice.GrimwildDicePool = dice.GrimwildDiePoolRoll;
CONFIG.Dice.rolls.push(dice.GrimwildDiePoolRoll);
+ CONFIG.Dice.GrimwildCrucibleRoll = dice.GrimwildCrucibleRoll;
+ CONFIG.Dice.rolls.push(dice.GrimwildCrucibleRoll);
// Define custom Document and DataModel classes
CONFIG.Actor.documentClass = GrimwildActor;
diff --git a/src/module/helpers/utils.js b/src/module/helpers/utils.js
index 14ca742..b89edcf 100644
--- a/src/module/helpers/utils.js
+++ b/src/module/helpers/utils.js
@@ -10,7 +10,9 @@ export async function preloadHandlebarsTemplates() {
// Actor partials
"systems/grimwild/templates/actor/parts/character-header.hbs",
"systems/grimwild/templates/actor/parts/monster-header.hbs",
- "systems/grimwild/templates/chat/roll-action.hbs"
+ "systems/grimwild/templates/chat/roll-action.hbs",
+ "systems/grimwild/templates/chat/roll-crucible.hbs",
+ "systems/grimwild/templates/chat/die-pool-action.hbs"
];
const paths = {};
diff --git a/src/templates/chat/roll-crucible.hbs b/src/templates/chat/roll-crucible.hbs
index 2b42037..d2bc9d5 100644
--- a/src/templates/chat/roll-crucible.hbs
+++ b/src/templates/chat/roll-crucible.hbs
@@ -3,16 +3,18 @@
{{ name }}
- {{ crucible.0 }}
- {{ crucible.1 }}
+ {{#each crucible as |result key|}}
+ {{ result }}
+ {{/each}}
- ${rollTable.results.map((result) => `${result.name} `).join('')}
+ ${rollTable.results.map((result) => `${result.name} `).join("")}
@@ -301,18 +301,18 @@ Hooks.once("ready", function () {
}
});
- document.addEventListener('click', async (event) => {
- if (event.target?.classList.contains('enriched-crucible-roll')) {
+ document.addEventListener("click", async (event) => {
+ if (event.target?.classList.contains("enriched-crucible-roll")) {
event.preventDefault();
const { uuid } = event.target.dataset;
if (uuid) {
const rollTable = await fromUuid(uuid);
if (rollTable.isCrucible()) {
- rollTable.rollCrucible({toMessage: true});
+ rollTable.rollCrucible({ toMessage: true });
}
}
}
- })
+ });
});
Hooks.once("renderHotbar", function () {
diff --git a/src/module/helpers/schema.mjs b/src/module/helpers/schema.mjs
index ccd3756..2133bd6 100644
--- a/src/module/helpers/schema.mjs
+++ b/src/module/helpers/schema.mjs
@@ -50,7 +50,7 @@ export class CrucibleTableField extends fields.SchemaField {
// Table roll instructions.
instructions: new fields.StringField(optionalString),
// Table results. Outer schema is columns, inner schema is rows.
- table: tableSchema,
+ table: tableSchema
};
super(tableFields, options, context);
diff --git a/src/module/sheets/item-sheet-vue.mjs b/src/module/sheets/item-sheet-vue.mjs
index 6a293c0..00de776 100644
--- a/src/module/sheets/item-sheet-vue.mjs
+++ b/src/module/sheets/item-sheet-vue.mjs
@@ -23,7 +23,7 @@ export class GrimwildItemSheetVue extends VueRenderingMixin(GrimwildBaseVueItemS
viewPermission: DOCUMENT_OWNERSHIP_LEVELS.LIMITED,
editPermission: DOCUMENT_OWNERSHIP_LEVELS.OWNER,
position: {
- width: 600,
+ width: 600
// height: 720,
},
window: {
@@ -41,7 +41,8 @@ export class GrimwildItemSheetVue extends VueRenderingMixin(GrimwildBaseVueItemS
createArrayEntry: this._createArrayEntry,
deleteArrayEntry: this._deleteArrayEntry,
rollPool: this._rollPool,
- rollCrucible: this._rollCrucible,
+ // @TODO restore when crucibles are added back to talents.
+ // rollCrucible: this._rollCrucible
},
// Custom property that's merged into `this.options`
dragDrop: [{ dragSelector: "[data-drag]", dropSelector: null }],
@@ -413,16 +414,18 @@ export class GrimwildItemSheetVue extends VueRenderingMixin(GrimwildBaseVueItemS
}
}
- /**
- * Handle rolling crucibles on the item sheet.
- * @todo abstract this to the item itself.
- *
- * @param {PointerEvent} event The originating click event
- * @param {HTMLElement} target The capturing HTML element which defined a [data-action]
- * @private
- */
- static async _rollCrucible(event, target) {
- event.preventDefault();
- const result = await this.document.system.rollCrucible({toMessage: true});
- }
+ // @TODO restore when crucibles are added back to talents.
+ // /**
+ // * Handle rolling crucibles on the item sheet.
+ // * @todo abstract this to the item itself.
+ // *
+ // * @param {PointerEvent} event The originating click event
+ // * @param {HTMLElement} target The capturing HTML element which defined a [data-action]
+ // * @returns
+ // * @private
+ // */
+ // static async _rollCrucible(event, target) {
+ // event.preventDefault();
+ // await this.document.system.rollCrucible({ toMessage: true });
+ // }
}
diff --git a/src/module/sheets/table-crucible-sheet.mjs b/src/module/sheets/table-crucible-sheet.mjs
index 88b6dae..28541da 100644
--- a/src/module/sheets/table-crucible-sheet.mjs
+++ b/src/module/sheets/table-crucible-sheet.mjs
@@ -17,12 +17,12 @@ export class GrimwildRollTableCrucibleSheet extends api.HandlebarsApplicationMix
icon: "fa-solid fa-table-list",
resizable: true
},
- position: {width: 720},
+ position: { width: 720 },
form: {
closeOnSubmit: false
},
actions: {
- drawResult: GrimwildRollTableCrucibleSheet.#onDrawResult,
+ drawResult: GrimwildRollTableCrucibleSheet.#onDrawResult
}
};
@@ -34,30 +34,30 @@ export class GrimwildRollTableCrucibleSheet extends api.HandlebarsApplicationMix
scrollable: ["table[data-results] tbody"],
root: true
},
- header: {template: "templates/sheets/roll-table/edit/header.hbs"},
- tabs: {template: "templates/generic/tab-navigation.hbs"},
+ header: { template: "templates/sheets/roll-table/edit/header.hbs" },
+ tabs: { template: "templates/generic/tab-navigation.hbs" },
results: {
template: "systems/grimwild/templates/roll-table/edit/crucible-results.hbs",
templates: ["templates/sheets/roll-table/result-details.hbs"],
scrollable: ["table[data-results] tbody"]
},
- summary: {template: "templates/sheets/roll-table/edit/summary.hbs"},
- footer: {template: "templates/generic/form-footer.hbs"}
+ summary: { template: "templates/sheets/roll-table/edit/summary.hbs" },
+ footer: { template: "templates/generic/form-footer.hbs" }
};
static MODE_PARTS = {
edit: ["header", "results", "footer"],
view: ["sheet", "footer"]
- }
+ };
grid = {
- 1: {1: '', 2: '', 3: '', 4: '', 5: '', 6: ''},
- 2: {1: '', 2: '', 3: '', 4: '', 5: '', 6: ''},
- 3: {1: '', 2: '', 3: '', 4: '', 5: '', 6: ''},
- 4: {1: '', 2: '', 3: '', 4: '', 5: '', 6: ''},
- 5: {1: '', 2: '', 3: '', 4: '', 5: '', 6: ''},
- 6: {1: '', 2: '', 3: '', 4: '', 5: '', 6: ''},
- }
+ 1: { 1: "", 2: "", 3: "", 4: "", 5: "", 6: "" },
+ 2: { 1: "", 2: "", 3: "", 4: "", 5: "", 6: "" },
+ 3: { 1: "", 2: "", 3: "", 4: "", 5: "", 6: "" },
+ 4: { 1: "", 2: "", 3: "", 4: "", 5: "", 6: "" },
+ 5: { 1: "", 2: "", 3: "", 4: "", 5: "", 6: "" },
+ 6: { 1: "", 2: "", 3: "", 4: "", 5: "", 6: "" }
+ };
/** @inheritDoc */
_prepareSubmitData(event, form, formData, updateData) {
@@ -70,14 +70,14 @@ export class GrimwildRollTableCrucibleSheet extends api.HandlebarsApplicationMix
/** @inheritDoc */
async submit(options) {
- if ( !this.isEditMode ) return;
+ if (!this.isEditMode) return;
return super.submit(options);
}
/** @inheritDoc */
_configureRenderOptions(options) {
- if ( !this.isEditable ) this.mode = "view";
- else if ( options.isFirstRender && !this.document.results.size ) this.mode = "edit";
+ if (!this.isEditable) this.mode = "view";
+ else if (options.isFirstRender && !this.document.results.size) this.mode = "edit";
return super._configureRenderOptions(options);
}
@@ -87,21 +87,21 @@ export class GrimwildRollTableCrucibleSheet extends api.HandlebarsApplicationMix
_configureRenderParts(options) {
const parts = super._configureRenderParts(options);
const allowedParts = this.constructor.MODE_PARTS[this.mode];
- for ( const partId in parts ) {
- if ( !allowedParts.includes(partId) ) delete parts[partId];
+ for (const partId in parts) {
+ if (!allowedParts.includes(partId)) delete parts[partId];
}
return parts;
}
_prepareTabs(group) {
- return {tabs: {}};
+ return { tabs: {} };
}
/** @inheritDoc */
async _preparePartContext(partId, context, options) {
context = await super._preparePartContext(partId, context, options);
- const {description, results, isOwner} = context.document;
- switch ( partId ) {
+ const { description, results, isOwner } = context.document;
+ switch (partId) {
case "results":
context.tab = context.tabs.results;
context.resultFields = foundry.documents.TableResult.schema.fields;
@@ -113,7 +113,7 @@ export class GrimwildRollTableCrucibleSheet extends api.HandlebarsApplicationMix
// context.formulaPlaceholder = `1d${results.size || 20}`;
// break;
case "sheet": // Lone view-mode part
- context.descriptionHTML = await TextEditor.implementation.enrichHTML(description, {secrets: isOwner});
+ context.descriptionHTML = await TextEditor.implementation.enrichHTML(description, { secrets: isOwner });
context.formula = context.source.formula || `1d${results.size || 20}`;
await this._prepareCrucibleGrid(context);
break;
@@ -132,7 +132,7 @@ export class GrimwildRollTableCrucibleSheet extends api.HandlebarsApplicationMix
label: "TABLE.ACTIONS.DrawResult"
}
];
- if ( this.isEditMode ) {
+ if (this.isEditMode) {
context.buttons.unshift({
type: "submit",
icon: "fa-solid fa-floppy-disk",
@@ -161,8 +161,8 @@ export class GrimwildRollTableCrucibleSheet extends api.HandlebarsApplicationMix
img: result.icon,
name: result.name,
fields: result.schema.fields,
- description: await TextEditor.implementation.enrichHTML(result.description, {relativeTo: result,
- secrets: result.isOwner}),
+ description: await TextEditor.implementation.enrichHTML(result.description, { relativeTo: result,
+ secrets: result.isOwner }),
documentLink: result.documentToAnchor()?.outerHTML,
weight: result.weight,
range,
@@ -172,7 +172,7 @@ export class GrimwildRollTableCrucibleSheet extends api.HandlebarsApplicationMix
async _prepareCrucibleGrid(context) {
const { results } = context.document;
- const getSortedResults = () => results.contents.sort(this._sortResults.bind(this)).slice(0,36);
+ const getSortedResults = () => results.contents.sort(this._sortResults.bind(this)).slice(0, 36);
context.results = await Promise.all(getSortedResults().map(this._prepareResult.bind(this)));
context.grid = this.document.getCrucibleTable();
}
@@ -194,26 +194,26 @@ export class GrimwildRollTableCrucibleSheet extends api.HandlebarsApplicationMix
}).bind(this.element);
// Allow draws with replacement by observers even if the Table is not editable
- if ( !options.parts.includes("footer") ) return;
+ if (!options.parts.includes("footer")) return;
const table = context.document;
const drawButton = this.element.querySelector("button[data-action=drawResult]");
- if ( table.replacement && table.testUserPermission(game.user, "OBSERVER") ) {
+ if (table.replacement && table.testUserPermission(game.user, "OBSERVER")) {
drawButton.disabled = false;
}
// Disallow draws without replacement from compendium Tables
- else if ( !table.replacement && table.pack ) {
+ else if (!table.replacement && table.pack) {
drawButton.disabled = true;
}
}
static async #onDrawResult(_event, button) {
- if ( this.form ) await this.submit({operation: {render: false}});
+ if (this.form) await this.submit({ operation: { render: false } });
button.disabled = true;
- await this.document.rollCrucible({toMessage: true});
+ await this.document.rollCrucible({ toMessage: true });
// Reenable the button if drawing with replacement since the draw won't trigger a sheet re-render
const table = this.document;
- if ( table.replacement ) button.disabled = false;
+ if (table.replacement) button.disabled = false;
}
}
diff --git a/src/vue/components/item/ItemAttributes.vue b/src/vue/components/item/ItemAttributes.vue
index 1f2de26..6f77783 100644
--- a/src/vue/components/item/ItemAttributes.vue
+++ b/src/vue/components/item/ItemAttributes.vue
@@ -1,5 +1,6 @@
-
+
+
From 0452a383a74e9f6de06c055a4c544334a2f355e1 Mon Sep 17 00:00:00 2001
From: Matt Smith
Date: Sun, 18 Jan 2026 14:41:43 -0600
Subject: [PATCH 09/11] Add button to create crucibles
---
src/module/grimwild.mjs | 48 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 48 insertions(+)
diff --git a/src/module/grimwild.mjs b/src/module/grimwild.mjs
index d8899bc..11e07e1 100644
--- a/src/module/grimwild.mjs
+++ b/src/module/grimwild.mjs
@@ -312,6 +312,46 @@ Hooks.once("ready", function () {
}
}
}
+
+ if (event.target?.classList.contains("create-crucible")) {
+ event.preventDefault();
+ try {
+ const crucibleName = await foundry.applications.api.DialogV2.prompt({
+ window: { title: "Create Crucible Table" },
+ content: `
+
+ ${game.i18n.localize("Name")}
+
+
`,
+ ok: {
+ label: "Create Crucible Table",
+ callback: (event, button, dialog) => button.form.elements.name.value
+ }
+ });
+ const defaultData = Array.fromRange(36,1).map(result => {
+ return {
+ name: "",
+ range: [result, result],
+ weight: 1,
+ type: "text"
+ };
+ });
+ RollTable.create({
+ name: crucibleName?.length > 0 ? crucibleName : "Crucible",
+ formula: "1d36",
+ results: defaultData,
+ flags: {
+ core: {
+ sheetClass: "grimwild.GrimwildRollTableCrucibleSheet"
+ }
+ }
+ });
+ }
+ catch (error) {
+ console.error(error);
+ return;
+ }
+ }
});
});
@@ -329,6 +369,14 @@ Hooks.on("renderSceneControls", (application, html, data) => {
SUSPENSE_TRACKER.render();
});
+Hooks.on("renderDocumentDirectory", (application, html, data) => {
+ if (data.documentName === "RollTable") {
+ html.querySelector(".header-actions").insertAdjacentHTML("afterbegin", `
+ Create Crucible
+ `);
+ }
+});
+
/* -------------------------------------------- */
/* Dice So Nice */
/* -------------------------------------------- */
From 301e8215bc16e7f0d7b1492a910b3a1c9fc27d72 Mon Sep 17 00:00:00 2001
From: Matt Smith
Date: Sun, 18 Jan 2026 14:45:21 -0600
Subject: [PATCH 10/11] i18n for crucibles
---
src/module/grimwild.mjs | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/module/grimwild.mjs b/src/module/grimwild.mjs
index 11e07e1..f7afb4b 100644
--- a/src/module/grimwild.mjs
+++ b/src/module/grimwild.mjs
@@ -315,16 +315,17 @@ Hooks.once("ready", function () {
if (event.target?.classList.contains("create-crucible")) {
event.preventDefault();
+ const label = game.i18n.format("DOCUMENT.Create", {type: "Crucible Table"});
try {
const crucibleName = await foundry.applications.api.DialogV2.prompt({
- window: { title: "Create Crucible Table" },
+ window: { title: label },
content: `
${game.i18n.localize("Name")}
`,
ok: {
- label: "Create Crucible Table",
+ label: label,
callback: (event, button, dialog) => button.form.elements.name.value
}
});
@@ -372,7 +373,7 @@ Hooks.on("renderSceneControls", (application, html, data) => {
Hooks.on("renderDocumentDirectory", (application, html, data) => {
if (data.documentName === "RollTable") {
html.querySelector(".header-actions").insertAdjacentHTML("afterbegin", `
- Create Crucible
+ ${game.i18n.format("DOCUMENT.Create", {type: "Crucible"})}
`);
}
});
From 71597e2c5b61d100efb55304062509373c0063a9 Mon Sep 17 00:00:00 2001
From: Matt Smith
Date: Sun, 18 Jan 2026 15:06:03 -0600
Subject: [PATCH 11/11] Add herbalism and GM crucibles
---
.../Herbalism_1_NyXKbhDPuI89I47r.yml | 747 ++++++++++++++++++
.../Herbalism_2_b3bE4RnBpBwA1ZHZ.yml | 747 ++++++++++++++++++
.../Herbalism_Crucible_YvQ4VZIy1yev1oq7.yml | 20 +
.../GM_Crucibles_czz9p07Cxj5KiIQu.yml | 57 ++
.../macros/GM_Crucible_IexJbzx3zjr1iw7R.yml | 87 --
.../Herbalism_Crucible_VTidfshGP2QVF5qd.yml | 57 ++
.../talents/Alchemist_KQM82DlCYc9UZiJD.yml | 12 +-
.../Arcane_Training_KBhSjWUjfwBAlCUq.yml | 2 -
.../talents/Herbalism_PbpG5CeFndV9DXjn.yml | 18 +-
.../Prepared_Spell_VpN3x2xMR2utoraH.yml | 15 +-
.../talents/Sorcery_MnncHMBYzPHIQJWG.yml | 16 +-
.../talents/Spellcraft_AxZp1G4i81EHnKl3.yml | 2 -
12 files changed, 1661 insertions(+), 119 deletions(-)
create mode 100644 src/packs/crucibles/Herbalism_1_NyXKbhDPuI89I47r.yml
create mode 100644 src/packs/crucibles/Herbalism_2_b3bE4RnBpBwA1ZHZ.yml
create mode 100644 src/packs/crucibles/Herbalism_Crucible_YvQ4VZIy1yev1oq7.yml
create mode 100644 src/packs/gm_toolkit/GM_Crucibles_czz9p07Cxj5KiIQu.yml
delete mode 100644 src/packs/macros/GM_Crucible_IexJbzx3zjr1iw7R.yml
create mode 100644 src/packs/rules/Herbalism_Crucible_VTidfshGP2QVF5qd.yml
diff --git a/src/packs/crucibles/Herbalism_1_NyXKbhDPuI89I47r.yml b/src/packs/crucibles/Herbalism_1_NyXKbhDPuI89I47r.yml
new file mode 100644
index 0000000..0f93ae9
--- /dev/null
+++ b/src/packs/crucibles/Herbalism_1_NyXKbhDPuI89I47r.yml
@@ -0,0 +1,747 @@
+name: Herbalism 1
+formula: 1d36
+results:
+ - name: choke
+ range:
+ - 1
+ - 1
+ weight: 1
+ type: text
+ _id: Ggz94YneEb4QvRfW
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.Ggz94YneEb4QvRfW'
+ - name: star
+ range:
+ - 2
+ - 2
+ weight: 1
+ type: text
+ _id: FwGXtX1Fn99Jpvmj
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.FwGXtX1Fn99Jpvmj'
+ - name: sun
+ range:
+ - 3
+ - 3
+ weight: 1
+ type: text
+ _id: 8FYGcWhgxC7kGWVh
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.8FYGcWhgxC7kGWVh'
+ - name: dream
+ range:
+ - 4
+ - 4
+ weight: 1
+ type: text
+ _id: gGnkpANwtuIeACHH
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.gGnkpANwtuIeACHH'
+ - name: mist
+ range:
+ - 5
+ - 5
+ weight: 1
+ type: text
+ _id: dp8MI1aMcX9CtOlZ
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.dp8MI1aMcX9CtOlZ'
+ - name: zap
+ range:
+ - 6
+ - 6
+ weight: 1
+ type: text
+ _id: t1JVpH6rGEpdLMS9
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.t1JVpH6rGEpdLMS9'
+ - name: sticky
+ range:
+ - 7
+ - 7
+ weight: 1
+ type: text
+ _id: EoWcBpgTuPLCUrn2
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.EoWcBpgTuPLCUrn2'
+ - name: stone
+ range:
+ - 8
+ - 8
+ weight: 1
+ type: text
+ _id: zTyaMpZ5zzNYiW1b
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.zTyaMpZ5zzNYiW1b'
+ - name: moon
+ range:
+ - 9
+ - 9
+ weight: 1
+ type: text
+ _id: D5W965pDfHppdBfo
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.D5W965pDfHppdBfo'
+ - name: feather
+ range:
+ - 10
+ - 10
+ weight: 1
+ type: text
+ _id: gA6NbEneoca5DXC9
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.gA6NbEneoca5DXC9'
+ - name: soot
+ range:
+ - 11
+ - 11
+ weight: 1
+ type: text
+ _id: 69Ek0jSVecma5f7e
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.69Ek0jSVecma5f7e'
+ - name: blast
+ range:
+ - 12
+ - 12
+ weight: 1
+ type: text
+ _id: 1M39ADQG7TWZTYon
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.1M39ADQG7TWZTYon'
+ - name: wool
+ range:
+ - 13
+ - 13
+ weight: 1
+ type: text
+ _id: poVVdmKAVADxEBxG
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.poVVdmKAVADxEBxG'
+ - name: dust
+ range:
+ - 14
+ - 14
+ weight: 1
+ type: text
+ _id: mSLsjcU4h5rCKJoM
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.mSLsjcU4h5rCKJoM'
+ - name: devil
+ range:
+ - 15
+ - 15
+ weight: 1
+ type: text
+ _id: jjUudfrgmhZBcFvV
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.jjUudfrgmhZBcFvV'
+ - name: wild
+ range:
+ - 16
+ - 16
+ weight: 1
+ type: text
+ _id: 8xmFzmXi4O7xVIbb
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.8xmFzmXi4O7xVIbb'
+ - name: freeze
+ range:
+ - 17
+ - 17
+ weight: 1
+ type: text
+ _id: 15kUg6mxdhWLDbCq
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.15kUg6mxdhWLDbCq'
+ - name: blood
+ range:
+ - 18
+ - 18
+ weight: 1
+ type: text
+ _id: 6qrHpx3q1IQ7AORm
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.6qrHpx3q1IQ7AORm'
+ - name: smoke
+ range:
+ - 19
+ - 19
+ weight: 1
+ type: text
+ _id: j4p9dGhGNk9cDvLO
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.j4p9dGhGNk9cDvLO'
+ - name: snake
+ range:
+ - 20
+ - 20
+ weight: 1
+ type: text
+ _id: btHv43EFHCXg0F2U
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.btHv43EFHCXg0F2U'
+ - name: honey
+ range:
+ - 21
+ - 21
+ weight: 1
+ type: text
+ _id: BjF1f4J7Wcuj5zS0
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.BjF1f4J7Wcuj5zS0'
+ - name: mirror
+ range:
+ - 22
+ - 22
+ weight: 1
+ type: text
+ _id: 0pJU4yUGps4bBoLM
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.0pJU4yUGps4bBoLM'
+ - name: sting
+ range:
+ - 23
+ - 23
+ weight: 1
+ type: text
+ _id: OgFvDSYCWbuadYS6
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.OgFvDSYCWbuadYS6'
+ - name: ink
+ range:
+ - 24
+ - 24
+ weight: 1
+ type: text
+ _id: appXJlCW2jxDHJ9v
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.appXJlCW2jxDHJ9v'
+ - name: shriek
+ range:
+ - 25
+ - 25
+ weight: 1
+ type: text
+ _id: KDWISChNtM9xPCjW
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.KDWISChNtM9xPCjW'
+ - name: mimic
+ range:
+ - 26
+ - 26
+ weight: 1
+ type: text
+ _id: k87xAECFSjdGNdf1
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.k87xAECFSjdGNdf1'
+ - name: goat
+ range:
+ - 27
+ - 27
+ weight: 1
+ type: text
+ _id: qRckRzAXK4gpmF4x
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.qRckRzAXK4gpmF4x'
+ - name: worm
+ range:
+ - 28
+ - 28
+ weight: 1
+ type: text
+ _id: 7C4fn6qD7IqFcD2U
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.7C4fn6qD7IqFcD2U'
+ - name: steel
+ range:
+ - 29
+ - 29
+ weight: 1
+ type: text
+ _id: 0flNnVwcptRVm4Gd
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.0flNnVwcptRVm4Gd'
+ - name: skunk
+ range:
+ - 30
+ - 30
+ weight: 1
+ type: text
+ _id: U9dqQaD6OEIiY31k
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.U9dqQaD6OEIiY31k'
+ - name: giggle
+ range:
+ - 31
+ - 31
+ weight: 1
+ type: text
+ _id: TgritmHxpqPoWCAb
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.TgritmHxpqPoWCAb'
+ - name: needle
+ range:
+ - 32
+ - 32
+ weight: 1
+ type: text
+ _id: lLYmhQNNLhGBlVGO
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.lLYmhQNNLhGBlVGO'
+ - name: night
+ range:
+ - 33
+ - 33
+ weight: 1
+ type: text
+ _id: ji36iruN3412WdDG
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.ji36iruN3412WdDG'
+ - name: swell
+ range:
+ - 34
+ - 34
+ weight: 1
+ type: text
+ _id: 2A0Q0M7hkAkRMUns
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.2A0Q0M7hkAkRMUns'
+ - name: faerie
+ range:
+ - 35
+ - 35
+ weight: 1
+ type: text
+ _id: 58PJdqYGij7QBpQO
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.58PJdqYGij7QBpQO'
+ - name: dragon
+ range:
+ - 36
+ - 36
+ weight: 1
+ type: text
+ _id: z9BC9EgYhROGqAMV
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!NyXKbhDPuI89I47r.z9BC9EgYhROGqAMV'
+flags:
+ core:
+ sheetClass: grimwild.GrimwildRollTableCrucibleSheet
+img: icons/tools/laboratory/mortar-powder-green.webp
+description: ''
+replacement: true
+displayRoll: true
+folder: YvQ4VZIy1yev1oq7
+ownership:
+ default: 0
+ UV77mtxQgW7KpS6B: 3
+_stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ createdTime: 1768770188173
+ modifiedTime: 1768770188173
+ lastModifiedBy: UV77mtxQgW7KpS6B
+_id: NyXKbhDPuI89I47r
+sort: 0
+_key: '!tables!NyXKbhDPuI89I47r'
diff --git a/src/packs/crucibles/Herbalism_2_b3bE4RnBpBwA1ZHZ.yml b/src/packs/crucibles/Herbalism_2_b3bE4RnBpBwA1ZHZ.yml
new file mode 100644
index 0000000..0df3bf6
--- /dev/null
+++ b/src/packs/crucibles/Herbalism_2_b3bE4RnBpBwA1ZHZ.yml
@@ -0,0 +1,747 @@
+name: Herbalism 2
+formula: 1d36
+results:
+ - name: cap
+ range:
+ - 1
+ - 1
+ weight: 1
+ type: text
+ _id: 6TIXx8S22NrYOsCs
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.6TIXx8S22NrYOsCs'
+ - name: lily
+ range:
+ - 2
+ - 2
+ weight: 1
+ type: text
+ _id: 0tARTg668qGxo8cK
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.0tARTg668qGxo8cK'
+ - name: thistle
+ range:
+ - 3
+ - 3
+ weight: 1
+ type: text
+ _id: 7RieJFdOkKLWulV6
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.7RieJFdOkKLWulV6'
+ - name: pod
+ range:
+ - 4
+ - 4
+ weight: 1
+ type: text
+ _id: hDekbNjoHemlwGdj
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.hDekbNjoHemlwGdj'
+ - name: stem
+ range:
+ - 5
+ - 5
+ weight: 1
+ type: text
+ _id: 6189uPh8YKq8VR6a
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.6189uPh8YKq8VR6a'
+ - name: petal
+ range:
+ - 6
+ - 6
+ weight: 1
+ type: text
+ _id: aXt7LO6DmPeMvDhN
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.aXt7LO6DmPeMvDhN'
+ - name: wort
+ range:
+ - 7
+ - 7
+ weight: 1
+ type: text
+ _id: 9LQ2Wfxr3MSGeP9T
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.9LQ2Wfxr3MSGeP9T'
+ - name: reed
+ range:
+ - 8
+ - 8
+ weight: 1
+ type: text
+ _id: 29xsDWRgk3pS4FC1
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.29xsDWRgk3pS4FC1'
+ - name: bell
+ range:
+ - 9
+ - 9
+ weight: 1
+ type: text
+ _id: PughcG6PYWhCafF6
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.PughcG6PYWhCafF6'
+ - name: bud
+ range:
+ - 10
+ - 10
+ weight: 1
+ type: text
+ _id: 4vQAYwQ1jQQh8peS
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.4vQAYwQ1jQQh8peS'
+ - name: shoot
+ range:
+ - 11
+ - 11
+ weight: 1
+ type: text
+ _id: EAvKMVSybyfznR3H
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.EAvKMVSybyfznR3H'
+ - name: bean
+ range:
+ - 12
+ - 12
+ weight: 1
+ type: text
+ _id: JbIRcY0CwV0IFFK1
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.JbIRcY0CwV0IFFK1'
+ - name: rose
+ range:
+ - 13
+ - 13
+ weight: 1
+ type: text
+ _id: pWeibFSUOevktFXl
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.pWeibFSUOevktFXl'
+ - name: flower
+ range:
+ - 14
+ - 14
+ weight: 1
+ type: text
+ _id: i9JggaqML94dlq93
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.i9JggaqML94dlq93'
+ - name: leaf
+ range:
+ - 15
+ - 15
+ weight: 1
+ type: text
+ _id: u5raAnu38HPfIZF7
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.u5raAnu38HPfIZF7'
+ - name: tongue
+ range:
+ - 16
+ - 16
+ weight: 1
+ type: text
+ _id: mPGp7ekZiTO0jz43
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.mPGp7ekZiTO0jz43'
+ - name: bark
+ range:
+ - 17
+ - 17
+ weight: 1
+ type: text
+ _id: 46tc7HSUaFX6LU2q
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.46tc7HSUaFX6LU2q'
+ - name: tuber
+ range:
+ - 18
+ - 18
+ weight: 1
+ type: text
+ _id: XgwAzO7b7VjwU5ZM
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.XgwAzO7b7VjwU5ZM'
+ - name: bush
+ range:
+ - 19
+ - 19
+ weight: 1
+ type: text
+ _id: Wy7VjL5ToL0Xp7iS
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.Wy7VjL5ToL0Xp7iS'
+ - name: root
+ range:
+ - 20
+ - 20
+ weight: 1
+ type: text
+ _id: qPHxoAXHFgGJZ1hV
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.qPHxoAXHFgGJZ1hV'
+ - name: wood
+ range:
+ - 21
+ - 21
+ weight: 1
+ type: text
+ _id: f4SNcix0yCcEY0sU
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.f4SNcix0yCcEY0sU'
+ - name: berry
+ range:
+ - 22
+ - 22
+ weight: 1
+ type: text
+ _id: MSgdPicGGJ5gbTIU
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.MSgdPicGGJ5gbTIU'
+ - name: funnel
+ range:
+ - 23
+ - 23
+ weight: 1
+ type: text
+ _id: rTl9NhQooGuCWsgd
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.rTl9NhQooGuCWsgd'
+ - name: vine
+ range:
+ - 24
+ - 24
+ weight: 1
+ type: text
+ _id: Yvxqft0FZEhz7RuS
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.Yvxqft0FZEhz7RuS'
+ - name: shroom
+ range:
+ - 25
+ - 25
+ weight: 1
+ type: text
+ _id: U56Ml623iOpIumbS
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.U56Ml623iOpIumbS'
+ - name: spine
+ range:
+ - 26
+ - 26
+ weight: 1
+ type: text
+ _id: ViNOPZl0FcRSb0mB
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.ViNOPZl0FcRSb0mB'
+ - name: grass
+ range:
+ - 27
+ - 27
+ weight: 1
+ type: text
+ _id: WZrG9HXcUYvq62Mh
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.WZrG9HXcUYvq62Mh'
+ - name: lace
+ range:
+ - 28
+ - 28
+ weight: 1
+ type: text
+ _id: D5idcCoisKO4UfYU
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.D5idcCoisKO4UfYU'
+ - name: moss
+ range:
+ - 29
+ - 29
+ weight: 1
+ type: text
+ _id: SKrPyFg6Da85qByF
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.SKrPyFg6Da85qByF'
+ - name: seed
+ range:
+ - 30
+ - 30
+ weight: 1
+ type: text
+ _id: Dp774RuOA1PGOSyz
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.Dp774RuOA1PGOSyz'
+ - name: sprout
+ range:
+ - 31
+ - 31
+ weight: 1
+ type: text
+ _id: G1fPh8GnaunR9CZC
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.G1fPh8GnaunR9CZC'
+ - name: shade
+ range:
+ - 32
+ - 32
+ weight: 1
+ type: text
+ _id: bjI2QFcHcgkPMFLW
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.bjI2QFcHcgkPMFLW'
+ - name: thorn
+ range:
+ - 33
+ - 33
+ weight: 1
+ type: text
+ _id: YH5mKVzqFLJNbBEV
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.YH5mKVzqFLJNbBEV'
+ - name: bane
+ range:
+ - 34
+ - 34
+ weight: 1
+ type: text
+ _id: sAbrc3Od6lKZ3xIh
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.sAbrc3Od6lKZ3xIh'
+ - name: branch
+ range:
+ - 35
+ - 35
+ weight: 1
+ type: text
+ _id: yXELF2ef8shF5tVi
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.yXELF2ef8shF5tVi'
+ - name: weed
+ range:
+ - 36
+ - 36
+ weight: 1
+ type: text
+ _id: xbZkFGkZ1UPUs9Zg
+ img: null
+ description: ''
+ drawn: false
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ lastModifiedBy: null
+ _key: '!tables.results!b3bE4RnBpBwA1ZHZ.xbZkFGkZ1UPUs9Zg'
+flags:
+ core:
+ sheetClass: grimwild.GrimwildRollTableCrucibleSheet
+img: icons/tools/laboratory/mortar-liquid-pink.webp
+description: ''
+replacement: true
+displayRoll: true
+folder: YvQ4VZIy1yev1oq7
+ownership:
+ default: 0
+ UV77mtxQgW7KpS6B: 3
+_stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ createdTime: 1768770190390
+ modifiedTime: 1768770190390
+ lastModifiedBy: UV77mtxQgW7KpS6B
+_id: b3bE4RnBpBwA1ZHZ
+sort: 0
+_key: '!tables!b3bE4RnBpBwA1ZHZ'
diff --git a/src/packs/crucibles/Herbalism_Crucible_YvQ4VZIy1yev1oq7.yml b/src/packs/crucibles/Herbalism_Crucible_YvQ4VZIy1yev1oq7.yml
new file mode 100644
index 0000000..31591ea
--- /dev/null
+++ b/src/packs/crucibles/Herbalism_Crucible_YvQ4VZIy1yev1oq7.yml
@@ -0,0 +1,20 @@
+type: RollTable
+folder: null
+name: Herbalism Crucible
+color: '#244503'
+sorting: a
+_id: YvQ4VZIy1yev1oq7
+description: ''
+sort: 0
+flags: {}
+_stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ createdTime: 1768770175903
+ modifiedTime: 1768770182369
+ lastModifiedBy: UV77mtxQgW7KpS6B
+_key: '!folders!YvQ4VZIy1yev1oq7'
diff --git a/src/packs/gm_toolkit/GM_Crucibles_czz9p07Cxj5KiIQu.yml b/src/packs/gm_toolkit/GM_Crucibles_czz9p07Cxj5KiIQu.yml
new file mode 100644
index 0000000..88552a9
--- /dev/null
+++ b/src/packs/gm_toolkit/GM_Crucibles_czz9p07Cxj5KiIQu.yml
@@ -0,0 +1,57 @@
+folder: V3M0EcoDlbmFxQPL
+name: GM Crucibles
+_id: czz9p07Cxj5KiIQu
+pages:
+ - sort: 100000
+ name: GM Crucibles
+ type: text
+ _id: JoYMnN7cbo9HmXPW
+ system: {}
+ title:
+ show: false
+ level: 1
+ image: {}
+ text:
+ format: 1
+ content: >-
+ @CRUCIBLE[Compendium.grimwild.crucibles.RollTable.KAx8TYWLRm4w3jMW]{GM
+ Crucible 1}
@CRUCIBLE[Compendium.grimwild.crucibles.RollTable.L0E7bnZtFjI51p3y]{GM
+ Crucible 2}
+ video:
+ controls: true
+ volume: 0.5
+ src: null
+ category: null
+ ownership:
+ default: -1
+ UV77mtxQgW7KpS6B: 3
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ createdTime: 1768769652047
+ modifiedTime: 1768769688239
+ lastModifiedBy: UV77mtxQgW7KpS6B
+ _key: '!journal.pages!czz9p07Cxj5KiIQu.JoYMnN7cbo9HmXPW'
+categories: []
+sort: 0
+ownership:
+ default: 0
+ UV77mtxQgW7KpS6B: 3
+flags: {}
+_stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ createdTime: 1768769643455
+ modifiedTime: 1768769643455
+ lastModifiedBy: UV77mtxQgW7KpS6B
+_key: '!journal!czz9p07Cxj5KiIQu'
diff --git a/src/packs/macros/GM_Crucible_IexJbzx3zjr1iw7R.yml b/src/packs/macros/GM_Crucible_IexJbzx3zjr1iw7R.yml
deleted file mode 100644
index c1e1438..0000000
--- a/src/packs/macros/GM_Crucible_IexJbzx3zjr1iw7R.yml
+++ /dev/null
@@ -1,87 +0,0 @@
-name: GM Crucible
-type: script
-_id: IexJbzx3zjr1iw7R
-author: Dl5Tvf37OuEHwdAh
-img: icons/svg/dice-target.svg
-scope: global
-command: >-
- // Macro to roll two different rolltables from a compendium called "crucibles"
-
-
- // Define the compendium and the rolltable names
-
- const compendiumName = "grimwild.crucibles"; // Adjust to the correct
- namespace for your system
-
- const rolltable1Name = "GM Crucible 1"; // Replace with the name of the first
- rolltable
-
- const rolltable2Name = "GM Crucible 2"; // Replace with the name of the second
- rolltable
-
-
- // Function to roll a table by name
-
- async function rollTable(compendiumName, tableName) {
- // Load the compendium
- const compendium = game.packs.get(compendiumName);
- if (!compendium) {
- ui.notifications.error(`Compendium "${compendiumName}" not found.`);
- return;
- }
-
- // Ensure the compendium is loaded
- await compendium.getIndex();
-
- // Find the rolltable entry by name
- const tableEntry = compendium.index.find((e) => e.name === tableName);
- if (!tableEntry) {
- ui.notifications.error(`RollTable "${tableName}" not found in compendium "${compendiumName}".`);
- return;
- }
-
- // Get the full rolltable document
- const table = await compendium.getDocument(tableEntry._id);
- if (!table) {
- ui.notifications.error(`Failed to load RollTable "${tableName}".`);
- return;
- }
-
- // Roll the table
- const rollResult = await table.roll();
- const resultText = rollResult.results
- .map((r) => r.text)
- .join(", "); // Combine results if multiple
-
- return resultText;
-
- }
-
-
- // Roll both tables
-
- const result1 = await rollTable(compendiumName, rolltable1Name);
-
- const result2 = await rollTable(compendiumName, rolltable2Name);
-
- ChatMessage.create({
- content: `GM Crucible Pick two and smash them together
- ${result1} ${result2} `
- });
-folder: null
-sort: 0
-ownership:
- default: 0
- Dl5Tvf37OuEHwdAh: 3
-flags: {}
-_stats:
- compendiumSource: null
- duplicateSource: null
- coreVersion: '13.345'
- systemId: grimwild
- systemVersion: 0.1.0
- createdTime: 1737218496094
- modifiedTime: 1737218905108
- lastModifiedBy: Dl5Tvf37OuEHwdAh
- exportSource: null
-_key: '!macros!IexJbzx3zjr1iw7R'
diff --git a/src/packs/rules/Herbalism_Crucible_VTidfshGP2QVF5qd.yml b/src/packs/rules/Herbalism_Crucible_VTidfshGP2QVF5qd.yml
new file mode 100644
index 0000000..618de39
--- /dev/null
+++ b/src/packs/rules/Herbalism_Crucible_VTidfshGP2QVF5qd.yml
@@ -0,0 +1,57 @@
+folder: vUGdoKGy7PZ2fdfW
+name: Herbalism Crucible
+_id: VTidfshGP2QVF5qd
+pages:
+ - sort: 100000
+ name: Herbalism Crucible
+ type: text
+ _id: w7rxyVPbxAskLAdq
+ system: {}
+ title:
+ show: false
+ level: 1
+ image: {}
+ text:
+ format: 1
+ content: >-
+ @CRUCIBLE[Compendium.grimwild.crucibles.RollTable.NyXKbhDPuI89I47r]{Herbalism
+ 1}
@CRUCIBLE[Compendium.grimwild.crucibles.RollTable.b3bE4RnBpBwA1ZHZ]{Herbalism
+ 2}
+ video:
+ controls: true
+ volume: 0.5
+ src: null
+ category: null
+ ownership:
+ default: -1
+ UV77mtxQgW7KpS6B: 3
+ flags: {}
+ _stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ createdTime: 1768770213971
+ modifiedTime: 1768770241904
+ lastModifiedBy: UV77mtxQgW7KpS6B
+ _key: '!journal.pages!VTidfshGP2QVF5qd.w7rxyVPbxAskLAdq'
+categories: []
+sort: 0
+ownership:
+ default: 0
+ UV77mtxQgW7KpS6B: 3
+flags: {}
+_stats:
+ compendiumSource: null
+ duplicateSource: null
+ exportSource: null
+ coreVersion: '13.351'
+ systemId: grimwild
+ systemVersion: 0.4.0
+ createdTime: 1768770207658
+ modifiedTime: 1768770207658
+ lastModifiedBy: UV77mtxQgW7KpS6B
+_key: '!journal!VTidfshGP2QVF5qd'
diff --git a/src/packs/talents/Alchemist_KQM82DlCYc9UZiJD.yml b/src/packs/talents/Alchemist_KQM82DlCYc9UZiJD.yml
index 628d26e..306f5b3 100644
--- a/src/packs/talents/Alchemist_KQM82DlCYc9UZiJD.yml
+++ b/src/packs/talents/Alchemist_KQM82DlCYc9UZiJD.yml
@@ -8,7 +8,9 @@ system:
Each session, you have a 4d Potions resource
pool. You can have a minor potion and roll the pool, or drop 1 and roll for
a major potion. You know recipes for your spell theorems, plus two more
- rolled on the Spell Crucible. Learn new recipes by sacrificing potions.
+ rolled on the
+ @UUID[Compendium.grimwild.rules.JournalEntry.WJWQtGwZcUubnCMj]{Spell
+ Crucible}. Learn new recipes by sacrificing potions.
core: false
notes:
description: Write down your recipes here.
@@ -33,11 +35,11 @@ flags: {}
_stats:
compendiumSource: null
duplicateSource: null
- coreVersion: '13.345'
+ coreVersion: '13.351'
systemId: grimwild
- systemVersion: 0.1.0
+ systemVersion: 0.4.0
createdTime: 1739542636102
- modifiedTime: 1739542636102
- lastModifiedBy: Dl5Tvf37OuEHwdAh
+ modifiedTime: 1768767417994
+ lastModifiedBy: UV77mtxQgW7KpS6B
exportSource: null
_key: '!items!KQM82DlCYc9UZiJD'
diff --git a/src/packs/talents/Arcane_Training_KBhSjWUjfwBAlCUq.yml b/src/packs/talents/Arcane_Training_KBhSjWUjfwBAlCUq.yml
index 8681e49..b6a80cf 100644
--- a/src/packs/talents/Arcane_Training_KBhSjWUjfwBAlCUq.yml
+++ b/src/packs/talents/Arcane_Training_KBhSjWUjfwBAlCUq.yml
@@ -32,8 +32,6 @@ system:
pool:
diceNum: 0
path: fighter
- crucible:
- instructions: ''
effects: []
sort: 0
ownership:
diff --git a/src/packs/talents/Herbalism_PbpG5CeFndV9DXjn.yml b/src/packs/talents/Herbalism_PbpG5CeFndV9DXjn.yml
index 36e029f..450e263 100644
--- a/src/packs/talents/Herbalism_PbpG5CeFndV9DXjn.yml
+++ b/src/packs/talents/Herbalism_PbpG5CeFndV9DXjn.yml
@@ -5,11 +5,13 @@ _id: PbpG5CeFndV9DXjn
img: icons/consumables/plants/leaf-hastate-glowing-green.webp
system:
description: >-
- Before each session, use the Herbalism Crucible to make two herb names
- (snakeberry, blastbane) . You have 1 minor potion of 1
- and 1 major potion of the other . The name is the touchstone.
- They lose effect after the session. One time only, you can have 1 mythic
- potion (choose after rolling) .
+ Before each session, use the
+ @UUID[Compendium.grimwild.rules.JournalEntry.VTidfshGP2QVF5qd]{Herbalism
+ Crucible} to make two herb names (snakeberry, blastbane) . You have
+ 1 minor potion of 1 and 1 major potion of the
+ other . The name is the touchstone. They lose effect after the
+ session. One time only, you can have 1 mythic potion (choose after
+ rolling) .
core: false
notes:
description: Write your two herb names here
@@ -41,11 +43,11 @@ flags: {}
_stats:
compendiumSource: null
duplicateSource: null
- coreVersion: '13.345'
+ coreVersion: '13.351'
systemId: grimwild
- systemVersion: 0.2.0
+ systemVersion: 0.4.0
createdTime: 1739109608751
- modifiedTime: 1750165688362
+ modifiedTime: 1768770300990
lastModifiedBy: UV77mtxQgW7KpS6B
exportSource: null
_key: '!items!PbpG5CeFndV9DXjn'
diff --git a/src/packs/talents/Prepared_Spell_VpN3x2xMR2utoraH.yml b/src/packs/talents/Prepared_Spell_VpN3x2xMR2utoraH.yml
index d26d628..795f285 100644
--- a/src/packs/talents/Prepared_Spell_VpN3x2xMR2utoraH.yml
+++ b/src/packs/talents/Prepared_Spell_VpN3x2xMR2utoraH.yml
@@ -16,13 +16,12 @@ system:
trackers:
- type: points
label: Story
- pool:
- diceNum: 0
- max: null
points:
- showSteps: true
value: 1
max: 1
+ showSteps: true
+ pool:
+ diceNum: 0
path: wizard
effects: []
sort: 0
@@ -33,11 +32,11 @@ flags: {}
_stats:
compendiumSource: null
duplicateSource: null
- coreVersion: '13.345'
+ coreVersion: '13.351'
systemId: grimwild
- systemVersion: 0.1.0
+ systemVersion: 0.4.0
createdTime: 1739542636102
- modifiedTime: 1739542636102
- lastModifiedBy: Dl5Tvf37OuEHwdAh
+ modifiedTime: 1768767485161
+ lastModifiedBy: UV77mtxQgW7KpS6B
exportSource: null
_key: '!items!VpN3x2xMR2utoraH'
diff --git a/src/packs/talents/Sorcery_MnncHMBYzPHIQJWG.yml b/src/packs/talents/Sorcery_MnncHMBYzPHIQJWG.yml
index ab1ece3..ff20eb7 100644
--- a/src/packs/talents/Sorcery_MnncHMBYzPHIQJWG.yml
+++ b/src/packs/talents/Sorcery_MnncHMBYzPHIQJWG.yml
@@ -19,9 +19,11 @@ system:
secondary wild surge —raw magic spirals out of your control.
Make a 2d story roll to see what happens. The
effect might stem from your touchstones, raw magical essence, or something
- chaotically random. Use the GM crucible or ask around your group for
- ideas.GROWTH : Every 2 levels, gain a new
- technique or magic path.
+ chaotically random. Use the
+ @UUID[Compendium.grimwild.gm_toolkit.JournalEntry.czz9p07Cxj5KiIQu]{GM
+ Crucibles} or ask around your group for ideas.GROWTH : Every 2 levels, gain a new technique or magic
+ path.
core: true
notes:
description: Write down your 4 magic paths and techniques here.
@@ -37,11 +39,11 @@ flags: {}
_stats:
compendiumSource: null
duplicateSource: null
- coreVersion: '13.345'
+ coreVersion: '13.351'
systemId: grimwild
- systemVersion: 0.1.0
+ systemVersion: 0.4.0
createdTime: 1739139357959
- modifiedTime: 1739139357959
- lastModifiedBy: Dl5Tvf37OuEHwdAh
+ modifiedTime: 1768769887601
+ lastModifiedBy: UV77mtxQgW7KpS6B
exportSource: null
_key: '!items!MnncHMBYzPHIQJWG'
diff --git a/src/packs/talents/Spellcraft_AxZp1G4i81EHnKl3.yml b/src/packs/talents/Spellcraft_AxZp1G4i81EHnKl3.yml
index 4bd256e..184f91e 100644
--- a/src/packs/talents/Spellcraft_AxZp1G4i81EHnKl3.yml
+++ b/src/packs/talents/Spellcraft_AxZp1G4i81EHnKl3.yml
@@ -40,8 +40,6 @@ system:
pool:
diceNum: 0
path: wizard
- crucible:
- instructions: ''
effects: []
sort: 0
ownership: