Skip to content

Commit

Permalink
feat: Issue xdy#59 Add support for advantage/disadvantage
Browse files Browse the repository at this point in the history
If you shift-click a skill a dialog where you can choose advantage/disadvantage, difficulty and modifiers show up.
Note that this skill roll dialog uses the Cepheus Engine rules, i.e. it adds a modifier for difficulty rather than change the target number. A roll above 8 is considered a success. The Effect of the roll is the result - 8.
I'd like to make the result row show 'Effect: 0' (or whatever the result was), but haven't figured out how yet, so that will have to wait for another time.
  • Loading branch information
xdy committed Aug 30, 2020
1 parent 491144b commit 67767da
Show file tree
Hide file tree
Showing 7 changed files with 243 additions and 48 deletions.
18 changes: 9 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 19 additions & 1 deletion src/module/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,28 @@ export const TWODSIX:any = {};

/**
* The sets of rules variants one can use
* TODO Should be loaded from json, really
* Not currently used for anything. TODO Remove?
* @type {Object}
*/
TWODSIX.VARIANTS = {
"ce": "Cepheus Engine",
}

TWODSIX.ROLLTYPES = {
Advantage: "3d6kh2",
Normal: "2d6",
Disadvantage: "3d6kl2"
}

//This is defined the CE way, but it's mathematically equivalent to other variants.
TWODSIX.DIFFICULTIES = {
Simple: 6,
Easy: 4,
Routine: 2,
Average: 0,
Difficult: -2,
VeryDifficult: -4,
Formidable: -6,
Impossible: -8
}

66 changes: 51 additions & 15 deletions src/module/sheets/TwodsixActorSheet.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import TwodsixItem from "../entities/TwodsixItem";
import {TwodsixRolls} from "../utils/TwodsixRolls";

export class TwodsixActorSheet extends ActorSheet {

/**
Expand Down Expand Up @@ -39,13 +42,13 @@ export class TwodsixActorSheet extends ActorSheet {
for (const i of sheetData.items) {
i.img = i.img || CONST.DEFAULT_TOKEN;
// Append to gear.
if (i.type === 'storage'){storage.push(i);}
if (i.type === 'inventory'){inventory.push(i);}
if (i.type === 'equipment'){equipment.push(i);}
if (i.type === 'weapon'){weapon.push(i);}
if (i.type === 'armor'){armor.push(i);}
if (i.type === 'augment'){augment.push(i);}
if (i.type === 'skills'){skills.push(i);}
if (i.type === 'storage') {storage.push(i);}
if (i.type === 'inventory') {inventory.push(i);}
if (i.type === 'equipment') {equipment.push(i);}
if (i.type === 'weapon') {weapon.push(i);}
if (i.type === 'armor') {armor.push(i);}
if (i.type === 'augment') {augment.push(i);}
if (i.type === 'skills') {skills.push(i);}
}
// Assign and return
actorData.storage = storage;
Expand Down Expand Up @@ -144,22 +147,55 @@ export class TwodsixActorSheet extends ActorSheet {
* @param {Event} event The originating click event
* @private
*/
_onRoll(event:{ preventDefault:() => void; currentTarget:any; }):void {
_onRoll(event: { preventDefault: any; currentTarget: any; shiftKey?: any; }):void {
event.preventDefault();
const element = event.currentTarget;
const dataset = element.dataset;

const itemId = $(event.currentTarget).parents('.item').attr('data-item-id');
const item = this.actor.getOwnedItem(itemId) as TwodsixItem;

if (dataset.roll) {
const roll = new Roll(dataset.roll, this.actor.data.data);
const label = dataset.label ? `Rolling ${dataset.label}` : '';
roll.roll().toMessage({
speaker: ChatMessage.getSpeaker({actor: this.actor}),
flavor: label
});
if (item.type === 'skills' && event.shiftKey) {
this.rollSkill(itemId, event, dataset);
} else {
const roll = new Roll(dataset.roll, this.actor.data.data);
const label = dataset.label ? `Rolling ${dataset.label}` : '';
roll.roll().toMessage({
speaker: ChatMessage.getSpeaker({actor: this.actor}),
flavor: label
});
}
}
}

rollSkill(
skillId:string,
event:{ preventDefault:() => void; currentTarget:any; },
dataset:{ roll:string; }
):Promise<any> {

const skillData = {};
const skills = this.getData().actor.skills;
if (!skills.length) {
return;
}

const rollParts = dataset.roll.split("+");

const flavorParts:string[] = [];
flavorParts.push(`${skills[0].name}`);

return TwodsixRolls.Roll({
parts: rollParts,
data: skillData,
flavorParts: flavorParts,
title: `${skills[0].name}`,
speaker: ChatMessage.getSpeaker({actor: this.getData().actor}),
});
}

//Unused, but something like is needed to support cascade/subskills, so letting it stay for now.
//Unused, but something like it is needed to support cascade/subskills, so letting it stay for now.
/**
* Handle skill upgrade
* @param {Event} event The originating click event
Expand Down
105 changes: 105 additions & 0 deletions src/module/utils/TwodsixRolls.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
export class TwodsixRolls {
static async Roll({
parts = [],
data = {},
flavorParts = [],
title = null,
speaker = null,
} = {}):Promise<unknown> {
let rolled = false;
const usefulParts = parts.filter(function (el) {
return el != '' && el;
});

const template = 'systems/twodsix/templates/chat/roll-dialog.html';
const dialogData = {
formula: usefulParts.join(' '),
data: data,
rollType: CONFIG.TWODSIX.ROLLTYPES.Normal,
rollTypes: CONFIG.TWODSIX.ROLLTYPES,
rollMode: game.settings.get('core', 'rollMode'),
rollModes: CONFIG.Dice.rollModes,
difficulty: CONFIG.TWODSIX.DIFFICULTIES.Normal,
difficulties: CONFIG.TWODSIX.DIFFICULTIES
};

const buttons = {
ok: {
label: "Roll",
icon: '<i class="fas fa-dice"></i>',
callback: (html) => {
roll = TwodsixRolls._handleRoll({
form: html[0].children[0],
rollParts: usefulParts,
flavorParts,
speaker,
});
rolled = true;
},
},
cancel: {
icon: '<i class="fas fa-times"></i>',
label: "Cancel",
},
};

const html = await renderTemplate(template, dialogData);
let roll:Roll;
return new Promise((resolve) => {
new Dialog({
title: title,
content: html,
buttons: buttons,
default: 'ok',
close: () => {
resolve(rolled ? roll : false);
},
}).render(true);
});
}

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static _handleRoll({form = null, rollParts = [], data = {}, flavorParts = [], speaker = null,}):Roll {
let rollMode = game.settings.get('core', 'rollMode');

if (form !== null) {
data['bonus'] = form.bonus.value;
data['difficulty'] = form.difficulty.value;
data['rollType'] = form.rollType.value;
data['rollMode'] = form.rollMode.value;
}

if (data['bonus'] && data['bonus'].length > 0) {
rollParts.push("" + data['bonus']);
}

if (data['difficulty'] && data['difficulty'].length > 0) {
rollParts.push("" + CONFIG.TWODSIX.DIFFICULTIES[data['difficulty']]);
flavorParts.unshift(`${data['difficulty']}`);
}

flavorParts.unshift("Rolling:");

if (data['rollType'] && data['rollType'].length > 0) {
rollParts[0] = CONFIG.TWODSIX.ROLLTYPES[data['rollType']];
flavorParts.push("with");
flavorParts.push(`${data['rollType']}`);
}

//So that the result is the Effect of the skill roll.
rollParts.push("-8");

const roll = new Roll(rollParts.join('+'), data).roll();
const flavor = flavorParts.join(' ');

rollMode = form ? form.rollMode.value : rollMode;
roll.toMessage(
{
speaker: speaker,
flavor: flavor
},
{rollMode: rollMode}
);
return roll;
}
}
2 changes: 1 addition & 1 deletion src/twodsix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,13 @@ Hooks.once('init', async function () {

/**
* Set an initiative formula for the system
* TODO Should be done via a setting
* @type {String}
*/
CONFIG.Combat.initiative = {
formula: "1d6",
decimals: 1
};

registerHandlebarsHelpers();
registerSettings();
await preloadTemplates();
Expand Down
39 changes: 17 additions & 22 deletions static/templates/actors/parts/actor-skills.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,22 @@

{{#each actor.skills as |item id|}}
<div class="skill">
<span class="item skill-container" >
<ol class="ol-no-indent">
<li class="item flexrow" data-item-id="{{item._id}}">
<span class="skill-container rollable" >
<span class="mini-dice centre"><img class="rollable" data-label="{{item.name}}" data-roll="2d6+{{data.mod}}+{{data.value}}" alt="roll skill" src="./systems/twodsix/assets/d6-icon.svg" /></span>
<span class="item-name rollable" data-label="{{item.name}}" data-roll="2d6+{{data.mod}}+{{data.value}}" alt="roll skill">{{item.name}}</span>
<span class="item-name centre rollable" data-label="{{item.name}}" data-roll="2d6+{{data.mod}}+{{data.value}}" alt="roll skill">{{data.value}}</span>
<span class="item-name centre rollable" data-label="{{item.name}}" data-roll="2d6+{{data.mod}}+{{data.value}}" alt="roll skill" for="skill-modifier">{{data.characteristic}} ({{numberFormat data.mod decimals=0 sign=true}})

</span>
<span class="total-output flex1 skill-mod rollable" data-label="{{item.name}}" data-roll="2d6+{{data.mod}}+{{data.value}}" alt="roll skill">{{data.total}}</span>


<span class="item-controls centre">
<a class="skl item-control item-edit" title="Edit Item"><i class="fas fa-edit"></i></a>
<a class="skl item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
</span>

</span>
</li>
</ol>
</span>
<span class="item skill-container">
<ol class="ol-no-indent">
<li class="item flexrow" data-item-id="{{item._id}}">
<span class="skill-container rollable">
<span class="mini-dice centre"><img class="rollable" data-label="{{item.name}}" data-roll="2d6+{{data.mod}}+{{data.value}}" src="./systems/twodsix/assets/d6-icon.svg"/></span>
<span class="item-name rollable" data-label="{{item.name}}" data-roll="2d6+{{data.mod}}+{{data.value}}">{{item.name}}</span>
<span class="item-name centre rollable" data-label="{{item.name}}" data-roll="2d6+{{data.mod}}+{{data.value}}">{{data.value}}</span>
<span class="item-name centre rollable" data-label="{{item.name}}" data-roll="2d6+{{data.mod}}+{{data.value}}" for="skill-modifier">{{data.characteristic}} ({{numberFormat data.mod decimals=0 sign=true}})</span>
<span class="total-output flex1 skill-mod rollable" data-label="{{item.name}}" data-roll="2d6+{{data.mod}}+{{data.value}}">{{data.total}}</span>
<span class="item-controls centre">
<a class="skl item-control item-edit" title="Edit Item"><i class="fas fa-edit"></i></a>
<a class="skl item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
</span>
</span>
</li>
</ol>
</span>
</div>
{{/each}}
41 changes: 41 additions & 0 deletions static/templates/chat/roll-dialog.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<form>
<div>Note that this skill roll dialog uses the Cepheus Engine rules, i.e. it adds a modifier for difficulty rather than change the target number. It then subtracts 8 from the result, showing the Effect of the skill roll.</div>
<div class="form-group">
<label>Difficulty
<select name="difficulty">
{{#select difficulty}}
{{#each difficulties as |label difficulty|}}
<option value="{{difficulty}}">{{difficulty}}</option>
{{/each}}
{{/select}}
</select>
</label>
</div>
<div class="form-group">
<label>Roll type
<select name="rollType">
{{#select rollType}}
{{#each rollTypes as |label type|}}
<option value="{{type}}">{{type}}</option>
{{/each}}
{{/select}}
</select>
</label>
</div>
<div class="form-group">
<label>Other modifiers
<input type="number" name="bonus" value="0" placeholder="0" onClick="this.select();"/>
</label>
</div>
<div class="form-group">
<label>Roll mode
<select name="rollMode">
{{#select rollMode}}
{{#each rollModes as |label mode|}}
<option value="{{mode}}">{{label}}</option>
{{/each}}
{{/select}}
</select>
</label>
</div>
</form>

0 comments on commit 67767da

Please sign in to comment.