Skip to content

Commit

Permalink
Initial fate reroll implementation
Browse files Browse the repository at this point in the history
Does not properly track artha for tests and rerolls for learning rolls
yet, works fine for stats and skills not being learned.
  • Loading branch information
StasTserk committed Jul 22, 2020
1 parent 2a7377f commit 1a7ce4a
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 44 deletions.
154 changes: 111 additions & 43 deletions module/rolls.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Ability, BWActor, TracksTests } from "./actor.js";
import { BWActorSheet } from "./bwactor-sheet.js";
import * as helpers from "./helpers.js";
import { Relationship, Skill, SkillDataRoot } from "./items/item.js";
import { Relationship, Skill, SkillData, SkillDataRoot } from "./items/item.js";

export async function handleRollable(
e: JQuery.ClickEvent<HTMLElement, null, HTMLElement, HTMLElement>, sheet: BWActorSheet): Promise<unknown> {
Expand Down Expand Up @@ -33,7 +33,63 @@ export async function handleRollable(
}

export async function handleFateReroll(target: HTMLButtonElement): Promise<unknown> {
return null;
const actor = game.actors.get(target.dataset.actorId || "") as BWActor;
const accessor = target.dataset.accessor || '';
const itemId = target.dataset.itemId || "";
let rollStat: Ability | SkillData;
if (target.dataset.rerollType === "stat") {
rollStat = getProperty(actor, `data.${accessor}`);
} else {
rollStat = (actor.getOwnedItem(itemId) as Skill).data.data;
}

const rollArray = target.dataset.dice?.split(',').map(s => parseInt(s, 10)) || [];
const successTarget = rollStat.shade === "B" ? 3 : (rollStat.shade === "G" ? 2 : 1);
let reroll: Roll | null;
if (rollStat.open) {
// only reroll dice if there were any traitors
const numDice = rollArray.filter(r => r <= successTarget).length ? 1 : 0;
reroll = rollDice(numDice, false, rollStat.shade);
} else {
const numDice = rollArray.filter(s => s === 6).length;
reroll = rollDice(numDice, true, rollStat.shade);
}

if (!reroll) { return; }

if (actor.data.data.fate !== "0") {
if (target.dataset.rerollType === "stat") {
const fateSpent = parseInt(getProperty(actor, `data.${accessor}.fate`) || "0", 10);
const updateData = {};
updateData[`${accessor}.fate`] = fateSpent + 1;
actor.update(updateData);
} else if (target.dataset.rerollType === "skill") {
const skill = actor.getOwnedItem(itemId) as Skill;
const fateSpent = parseInt(skill.data.data.fate, 10) || 0;
skill.update({ 'data.fate': fateSpent + 1 }, {});
}

const actorFateCount = parseInt(actor.data.data.fate, 10);
actor.update({ 'data.fate': actorFateCount -1 });
}

const successes = parseInt(target.dataset.successes || "0", 10);
const obstacleTotal = parseInt(target.dataset.difficulty || "0", 10);
const newSuccesses = parseInt(reroll.result, 10);
const success = (newSuccesses + successes) >= obstacleTotal;
const data: FateRerollMessageData = {
rolls: rollArray.map(r => { return { roll: r, success: r > successTarget }; }),
rerolls: reroll.dice[0].rolls,
successes,
obstacleTotal,
newSuccesses,
success
};
const html = await renderTemplate(templates.rerollChatMessage, data);
return ChatMessage.create({
content: html,
speaker: ChatMessage.getSpeaker({actor})
});
}


Expand Down Expand Up @@ -108,45 +164,45 @@ async function handlePtgsRoll(target: HTMLButtonElement, sheet: BWActorSheet, sh
}

async function ptgsRollCallback(
dialogHtml: JQuery<HTMLElement>,
stat: Ability,
sheet: BWActorSheet,
shrugging: boolean) {
const baseData = extractBaseData(dialogHtml, sheet);
const exp = parseInt(stat.exp, 10);
const dieSources = buildDiceSourceObject(exp, baseData.aDice, baseData.bDice, 0, 0, 0);
const dg = helpers.difficultyGroup(exp + baseData.bDice, baseData.diff);
const numDice = exp + baseData.bDice + baseData.aDice - baseData.woundDice;

const roll = rollDice(numDice, stat.open, stat.shade);
if (!roll) { return; }

const isSuccessful = parseInt(roll.result, 10) >= (baseData.diff);

const data: RollChatMessageData = {
name: shrugging ? "Shrug It Off Health Test" : "Grit Your Teeth Health Test",
successes: roll.result,
difficulty: baseData.diff,
nameClass: getRollNameClass(stat.open, stat.shade),
obstacleTotal: baseData.obstacleTotal -= baseData.obPenalty,
success: isSuccessful,
rolls: roll.dice[0].rolls,
difficultyGroup: dg,
dieSources
};
if (isSuccessful) {
const accessor = shrugging ? "data.ptgs.shrugging" : "data.ptgs.gritting";
const updateData = {};
updateData[accessor] = true;
sheet.actor.update(updateData);
}
sheet.actor.addAttributeTest(stat, "Health", "data.health", dg, isSuccessful);
const messageHtml = await renderTemplate(templates.attrMessage, data);
return ChatMessage.create({
content: messageHtml,
speaker: ChatMessage.getSpeaker({actor: sheet.actor})
});
dialogHtml: JQuery<HTMLElement>,
stat: Ability,
sheet: BWActorSheet,
shrugging: boolean) {
const baseData = extractBaseData(dialogHtml, sheet);
const exp = parseInt(stat.exp, 10);
const dieSources = buildDiceSourceObject(exp, baseData.aDice, baseData.bDice, 0, 0, 0);
const dg = helpers.difficultyGroup(exp + baseData.bDice, baseData.diff);
const numDice = exp + baseData.bDice + baseData.aDice - baseData.woundDice;

const roll = rollDice(numDice, stat.open, stat.shade);
if (!roll) { return; }

const isSuccessful = parseInt(roll.result, 10) >= (baseData.diff);

const data: RollChatMessageData = {
name: shrugging ? "Shrug It Off Health Test" : "Grit Your Teeth Health Test",
successes: roll.result,
difficulty: baseData.diff,
nameClass: getRollNameClass(stat.open, stat.shade),
obstacleTotal: baseData.obstacleTotal -= baseData.obPenalty,
success: isSuccessful,
rolls: roll.dice[0].rolls,
difficultyGroup: dg,
dieSources
};
if (isSuccessful) {
const accessor = shrugging ? "data.ptgs.shrugging" : "data.ptgs.gritting";
const updateData = {};
updateData[accessor] = true;
sheet.actor.update(updateData);
}
sheet.actor.addAttributeTest(stat, "Health", "data.health", dg, isSuccessful);
const messageHtml = await renderTemplate(templates.attrMessage, data);
return ChatMessage.create({
content: messageHtml,
speaker: ChatMessage.getSpeaker({actor: sheet.actor})
});
}


async function handleAttrRoll(target: HTMLButtonElement, sheet: BWActorSheet): Promise<unknown> {
Expand Down Expand Up @@ -365,6 +421,7 @@ async function learningRollCallback(
if (!roll) { return; }
const isSuccessful = parseInt(roll.result, 10) >= baseData.obstacleTotal;
const fateReroll = buildFateRerollData(sheet.actor, roll, undefined, skill._id);
if (fateReroll) { fateReroll!.type = "learning"; }

const data: RollChatMessageData = {
name: `Beginner's Luck ${skill.data.name} Test`,
Expand Down Expand Up @@ -577,17 +634,18 @@ function buildFateRerollData(actor: BWActor, roll: Roll, accessor?: string, item
}
const coreData: FateRerollData = {
dice: roll.dice[0].rolls.map(r => r.roll).join(","),
type: "stat",
actorId: actor._id,
};
if (accessor) {
return {
accessor,
type: "stat",
...coreData
};
} else {
return {
itemId,
type: "skill",
...coreData
};
}
Expand Down Expand Up @@ -802,7 +860,8 @@ const templates = {
skillDialog: "systems/burningwheel/templates/chat/skill-dialog.html",
skillMessage: "systems/burningwheel/templates/chat/roll-message.html",
statDialog: "systems/burningwheel/templates/chat/roll-dialog.html",
statMessage: "systems/burningwheel/templates/chat/roll-message.html"
statMessage: "systems/burningwheel/templates/chat/roll-message.html",
rerollChatMessage: "systems/burningwheel/templates/chat/fate-reroll-message.html"
};


Expand Down Expand Up @@ -857,10 +916,19 @@ export interface RollChatMessageData {
fateReroll?: FateRerollData;
}

export interface FateRerollMessageData {
rolls: { roll: number, success: boolean }[];
rerolls: { roll: number, success: boolean }[];
success: boolean;
successes: number;
newSuccesses: number;
obstacleTotal: number;
}

export interface FateRerollData {
dice: string;
actorId: string;
type: "stat" | "skill";
type?: "stat" | "skill" | "learning";
itemId?: string;
accessor?: string;
}
9 changes: 8 additions & 1 deletion styles/chat/roll.scss
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@
&.right-align {
text-align: right;
}

&.vertical-divider {
border: 0;
border-left: 1px solid #333;
border-right: 1px solid #ccc;
margin: 1px 5px;
}
}

.roll-half-width {
Expand Down Expand Up @@ -73,7 +80,7 @@
font-size: 12px;
font-weight: bold;
text-align: center;
margin-left: 5px;
margin: 0px 2px;
}

.roll-Routine {
Expand Down
35 changes: 35 additions & 0 deletions templates/chat/fate-reroll-message.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<div class="chat-message flex-row">
<div class="roll-full-width message-title">
Fate Reroll
</div>
<div class="roll-half-width">
<label>Successes</label>
<div>{{ successes }} + {{ newSuccesses }} </div>
</div>
<div class="roll-half-width">
<label>Obstacle</label>
<div>{{ obstacleTotal }}</div>
</div>
<div class="roll-dice roll-full-width flex-row">
{{#each rolls as |r|}}
<div class="roll-die" data-success="{{r.success}}">
{{r.roll}}
</div>
{{/each}}
<div class="vertical-divider"></div>
{{#each rerolls as |r|}}
<div class="roll-die" data-success="{{r.success}}">
{{r.roll}}
</div>
{{/each}}
</div>
{{#if success}}
<div class="roll-result roll-full-width roll-success">
Success!
</div>
{{else}}
<div class="roll-result roll-full-width roll-failure">
Failure!
</div>
{{/if}}
</div>

0 comments on commit 1a7ce4a

Please sign in to comment.