Skip to content

Commit cb73ecb

Browse files
authored
Merge pull request #70 from asacolips-projects/feature/asacolips/talent-crucibles
First pass at crucibles
2 parents 5acd9e0 + 71597e2 commit cb73ecb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+6471
-1815
lines changed

src/lang/en.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ GRIMWILD:
9898
SheetLabels:
9999
Actor: Grimwild Actor Sheet
100100
Item: Grimwild Item Sheet
101+
RollTable: Grimwild Crucible Sheet
101102
Actor:
102103
Plural:
103104
character: Characters

src/module/controls/suspense.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ class SuspenseTracker {
165165
const quickPoolHtml = isGM || quickPoolsVisibleToPlayers ? getScenePools() : "";
166166
susControl.innerHTML = `${susControlInnerHTML}${quickPoolHtml}`;
167167
const susElement = document.querySelector("#sus-control");
168-
const poolElement = document.querySelector('.quick-pool-inner');
168+
const poolElement = document.querySelector(".quick-pool-inner");
169169

170170
if (isGM && susElement) {
171171
susElement.querySelector("#js-sus-up").onclick = () => setSuspense(getSuspense() + 1);

src/module/data/actor-character.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ export default class GrimwildCharacter extends GrimwildActorBase {
357357
// Update the active turn.
358358
const combatantTurn = combat.turns.findIndex((c) => c.id === combatant.id);
359359
if (combatantTurn !== undefined) {
360-
combat.update({'turn': combatantTurn});
360+
combat.update({ turn: combatantTurn });
361361
}
362362
}
363363
}

src/module/data/item-arcana.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export default class GrimwildArcana extends GrimwildItemBase {
1919

2020
// Arcana type.
2121
schema.tier = new fields.StringField({
22-
initial: 'minor',
22+
initial: "minor"
2323
});
2424

2525
// Arbitrary notes.

src/module/data/item-talent.mjs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,23 @@ export default class GrimwildTalent extends GrimwildItemBase {
5151
})
5252
}));
5353

54+
// @TODO refactor this to use roll tables.
55+
// Crucible.
56+
// schema.crucible = new CrucibleTableField();
57+
5458
return schema;
5559
}
5660

61+
// async rollCrucible(options = {}) {
62+
// const result = new grimwild.rollCrucible('{2d6}', {}, {crucible: this.crucible});
63+
// await result.roll();
64+
// if (options.toMessage) {
65+
// result.toMessage();
66+
// }
67+
68+
// return result;
69+
// }
70+
5771
/**
5872
* Migrate source data from prior format to the new specification.
5973
*

src/module/dice/_module.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export { default as GrimwildRoll } from "./rolls.mjs";
2+
export { default as GrimwildCrucibleRoll } from "./crucible-rolls.mjs";
23
export { default as GrimwildDiePoolRoll } from "./die-pools.mjs";

src/module/dice/crucible-rolls.mjs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// @TODO make this actually work.
2+
export default class GrimwildCrucibleRoll extends Roll {
3+
static CHAT_TEMPLATE = "systems/grimwild/templates/chat/roll-crucible.hbs";
4+
5+
constructor(formula, data, options) {
6+
super(formula, data, options);
7+
if (game.dice3d && game.settings.get("grimwild", "diceSoNiceOverride")) {
8+
if (!this.options.appearance) this.options.appearance = {};
9+
this.options.appearance.system = "grimwild";
10+
this.options.appearance.colorset = "grimwild-dark";
11+
}
12+
13+
if (!this.options.crucible) {
14+
throw new Error("A crucible object must be supplied in options.crucible for this roll.");
15+
}
16+
}
17+
18+
async render({ flavor, template=this.constructor.CHAT_TEMPLATE, isPrivate=false }={}) {
19+
if (!this._evaluated) await this.evaluate();
20+
const dice = this.dice[0].results;
21+
22+
const chatData = {
23+
formula: isPrivate ? "???" : this._formula,
24+
flavor: isPrivate ? null : flavor ?? this.options.flavor,
25+
user: game.user.id,
26+
tooltip: isPrivate ? "" : await this.getTooltip(),
27+
stat: this.options.stat,
28+
dice: dice,
29+
name: this.options.crucible?.name ?? "Crucible",
30+
crucible: {
31+
0: this.options.crucible.table[dice[0].result][dice[1].result],
32+
1: this.options.crucible.table[dice[1].result][dice[0].result]
33+
},
34+
isPrivate: isPrivate
35+
};
36+
37+
return foundry.applications.handlebars.renderTemplate(template, chatData);
38+
}
39+
}

src/module/dice/rolls.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export default class GrimwildRoll extends Roll {
6767
chatData.result = successToResult(chatData.success);
6868
chatData.rawResult = successToResult(chatData.rawSuccess);
6969
chatData.isCut = chatData.success !== chatData.rawSuccess;
70-
chatData.isFail = ['disaster', 'grim', 'messy'].includes(chatData.result);
70+
chatData.isFail = ["disaster", "grim", "messy"].includes(chatData.result);
7171

7272
// Separate assist dice from other dice
7373
if (this.options?.assists) {

src/module/documents/chat-message.mjs

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { GrimwildActor } from "./actor.mjs";
2-
31
export class GrimwildChatMessage extends ChatMessage {
42
/** @inheritDoc */
53
async renderHTML(...args) {
@@ -88,7 +86,7 @@ export class GrimwildChatMessage extends ChatMessage {
8886
return;
8987
}
9088
}
91-
else if (['applyMark', 'applyHarm'].includes(action)) {
89+
else if (["applyMark", "applyHarm"].includes(action)) {
9290
if (damageTaken) {
9391
element.setAttribute("disabled", true);
9492
return;
@@ -107,7 +105,7 @@ export class GrimwildChatMessage extends ChatMessage {
107105
return {
108106
updateSpark: this._updateSpark,
109107
applyMark: this._applyHarm,
110-
applyHarm: this._applyHarm,
108+
applyHarm: this._applyHarm
111109
};
112110
}
113111

@@ -199,25 +197,23 @@ export class GrimwildChatMessage extends ChatMessage {
199197
let harmUpdate = {};
200198
// Handle marks.
201199
if (stat) {
202-
if (['bra', 'agi', 'wit', 'pre'].includes(stat)) {
200+
if (["bra", "agi", "wit", "pre"].includes(stat)) {
203201
const isMarked = actor.system.stats[stat].marked;
204202
if (!isMarked) {
205203
update[`system.stats.${stat}.marked`] = true;
206204
}
205+
else if (["bra", "agi"].includes(stat)) {
206+
harmUpdate = this.calculateHarm(actor, "bloodied");
207+
}
207208
else {
208-
if (['bra', 'agi'].includes(stat)) {
209-
harmUpdate = this.calculateHarm(actor, 'bloodied');
210-
}
211-
else {
212-
harmUpdate = this.calculateHarm(actor, 'rattled');
213-
}
209+
harmUpdate = this.calculateHarm(actor, "rattled");
214210
}
215211
}
216212
}
217213

218214
// Handle harm.
219215
if (harm) {
220-
if (['bloodied', 'rattled'].includes(harm)) {
216+
if (["bloodied", "rattled"].includes(harm)) {
221217
harmUpdate = this.calculateHarm(actor, harm);
222218
}
223219
}
@@ -255,21 +251,19 @@ export class GrimwildChatMessage extends ChatMessage {
255251
*/
256252
calculateHarm(actor, harm) {
257253
const harmPools = game.settings.get("grimwild", "enableHarmPools");
258-
const maxHarm = game.settings.get("grimwild", `max${harm === 'bloodied' ? 'Bloodied' : 'Rattled'}`) ?? 1;
254+
const maxHarm = game.settings.get("grimwild", `max${harm === "bloodied" ? "Bloodied" : "Rattled"}`) ?? 1;
259255
const update = {};
260-
if (!actor.system[harm == 'bloodied' ? 'isBloodied' : 'isRattled']) {
256+
if (!actor.system[harm === "bloodied" ? "isBloodied" : "isRattled"]) {
261257
update[`system.${harm}.marked`] = true;
262258
if (harmPools) {
263259
update[`system.${harm}.pool.diceNum`] = 1;
264260
}
265261
}
262+
else if (!harmPools || actor.system[harm].pool.diceNum >= maxHarm) {
263+
update["system.dropped"] = true;
264+
}
266265
else {
267-
if (!harmPools || actor.system[harm].pool.diceNum >= maxHarm) {
268-
update[`system.dropped`] = true;
269-
}
270-
else {
271-
update[`system.${harm}.pool.diceNum`] = actor.system[harm].pool.diceNum + 1;
272-
}
266+
update[`system.${harm}.pool.diceNum`] = actor.system[harm].pool.diceNum + 1;
273267
}
274268

275269
return update;
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
export class GrimwildRollTable extends foundry.documents.RollTable {
2+
async _preUpdate(changes, options, user) {
3+
await super._preUpdate(changes, options, user);
4+
5+
if (changes?.flags?.core?.sheetClass === "grimwild.GrimwildRollTableCrucibleSheet") {
6+
if (this.results && this.results.size < 36) {
7+
const results = Array.fromRange(36 - this.results.size, 1).map((result) => {
8+
return {
9+
name: "",
10+
range: [result, result],
11+
weight: 1,
12+
_id: foundry.utils.randomID()
13+
};
14+
});
15+
changes.formula = "1d36";
16+
changes.results = results;
17+
}
18+
}
19+
}
20+
21+
async roll({ roll, recursive=true, _depth=0 }={}) {
22+
if (this.isCrucible()) {
23+
// @todo tie this to the rollCrucible() method.
24+
return super.roll({ roll, recursive, _depth });
25+
}
26+
27+
return super.roll({ roll, recursive, _depth });
28+
29+
}
30+
31+
isCrucible() {
32+
return this.getFlag("core", "sheetClass") === "grimwild.GrimwildRollTableCrucibleSheet";
33+
}
34+
35+
getCrucibleTable() {
36+
if (this.isCrucible()) {
37+
const grid = {
38+
1: { 1: "", 2: "", 3: "", 4: "", 5: "", 6: "" },
39+
2: { 1: "", 2: "", 3: "", 4: "", 5: "", 6: "" },
40+
3: { 1: "", 2: "", 3: "", 4: "", 5: "", 6: "" },
41+
4: { 1: "", 2: "", 3: "", 4: "", 5: "", 6: "" },
42+
5: { 1: "", 2: "", 3: "", 4: "", 5: "", 6: "" },
43+
6: { 1: "", 2: "", 3: "", 4: "", 5: "", 6: "" }
44+
};
45+
let row = 1;
46+
let col = 1;
47+
let count = 0;
48+
this.results.forEach((result) => {
49+
if (count < 36) {
50+
grid[row][col] = result.name;
51+
col++;
52+
if (col === 7) {
53+
row++;
54+
col = 1;
55+
}
56+
count++;
57+
}
58+
});
59+
60+
return grid;
61+
}
62+
}
63+
64+
async rollCrucible({ toMessage=true }={}) {
65+
const crucibleRoll = new grimwild.rollCrucible("{2d6}", {}, {
66+
crucible: {
67+
name: this.name,
68+
instructions: "",
69+
table: this.getCrucibleTable()
70+
}
71+
});
72+
73+
await crucibleRoll.roll();
74+
if (toMessage) {
75+
crucibleRoll.toMessage();
76+
}
77+
78+
return crucibleRoll;
79+
}
80+
}

0 commit comments

Comments
 (0)