Skip to content

Commit

Permalink
fix(spell-import): Importing Spell List gives an error
Browse files Browse the repository at this point in the history
Introduced version checking as well to prevent problems with mismatched
character sheet versions. Partial fix for #12.
closes #334
  • Loading branch information
symposion committed Feb 25, 2017
1 parent ddbbd27 commit 88019de
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 35 deletions.
27 changes: 21 additions & 6 deletions lib/command-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ class Command {
return this;
}

handle(args, selection, cmdString, playerIsGM, playerId) {
handle(args, selection, cmdString, playerIsGM, playerId, requiredCharVersion) {
if (!playerIsGM && this.gmOnly) {
throw new UserError('You must be a GM to run this command');
}
Expand All @@ -157,7 +157,8 @@ class Command {
},
});

startOptions.selected = this.selectionSpec && processSelection(selection || [], this.selectionSpec, this.roll20);
startOptions.selected =
this.selectionSpec && processSelection(selection || [], this.selectionSpec, this.roll20, requiredCharVersion);
const finalOptions = _.chain(args)
.reduce((options, arg) => {
if (!_.some(this.parsers, parser => parser(arg, options.errors, options))) {
Expand Down Expand Up @@ -224,14 +225,23 @@ class Command {
}
}

function processSelection(selection, constraints, roll20) {
function processSelection(selection, constraints, roll20, requiredCharVersion) {
return _.reduce(constraints, (result, constraintDetails, type) => {
const objects = _.chain(selection)
.where({ _type: type === 'character' ? 'graphic' : type })
.map(selected => roll20.getObj(selected._type, selected._id))
.map((object) => {
if (type === 'character' && object) {
return roll20.getObj('character', object.get('represents'));
const char = roll20.getObj('character', object.get('represents'));
if (!constraintDetails.anyVersion) {
const version = roll20.getAttrByName(char.id, 'version');
if (version !== requiredCharVersion) {
throw new UserError(`Character ${char.get('name')} is not at the required sheet version ` +
`[${requiredCharVersion}], but instead [${version}]. Try opening the character sheet or running ` +
'!shaped-update-character to update it.');
}
}
return char;
}
return object;
})
Expand Down Expand Up @@ -262,7 +272,12 @@ function processSelection(selection, constraints, roll20) {

module.exports = function commandParser(rootCommand, roll20, errorHandler) {
const commands = {};
let requiredCharVersion = null;
return {
setRequiredCharacterVersion(version) {
requiredCharVersion = version;
},

addCommand(cmds, handler, gmOnly) {
const command = new Command(this, handler, roll20, _.isArray(cmds) ? cmds.join(',') : cmds, gmOnly);
(_.isArray(cmds) ? cmds : [cmds]).forEach(cmdString => (commands[cmdString] = command));
Expand All @@ -286,8 +301,8 @@ module.exports = function commandParser(rootCommand, roll20, errorHandler) {
if (!cmd) {
throw new UserError(`Unrecognised command ${prefix}${cmdName}`);
}
const returnVal =
cmd.handle(parts, msg.selected, `${prefix}${cmdName}`, roll20.playerIsGM(msg.playerid), msg.playerid);
const returnVal = cmd.handle(parts, msg.selected, `${prefix}${cmdName}`,
roll20.playerIsGM(msg.playerid), msg.playerid, requiredCharVersion);
if (returnVal instanceof Promise) {
returnVal.catch(errorHandler);
}
Expand Down
1 change: 1 addition & 0 deletions lib/importer.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ class Importer extends ShapedModule {
character: {
min: 0,
max: Infinity,
anyVersion: true,
},
})
.option('all', ShapedConfig.booleanValidator)
Expand Down
9 changes: 9 additions & 0 deletions lib/shaped-script.js
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,15 @@ function ShapedScripts(logger, myState, roll20, parser, entityLookup, reporter)
this.checkInstall = function checkInstall() {
logger.info('-=> ShapedScripts %%GULP_INJECT_VERSION%% <=-');
Migrator.migrateShapedConfig(myState, logger);
const character = roll20.createObj('character', { name: 'SHAPED_VERSION_TESTER' });
setTimeout(() => {
roll20.createAttrWithWorker(character.id, 'sheet_opened', 1, () => {
const version = roll20.getAttrByName(character.id, 'version');
character.remove();
commandProc.setRequiredCharacterVersion(version);
logger.info('Detected sheet version as : $$$', version);
});
}, 400);
};

this.wrapHandler = function wrapHandler(handler) {
Expand Down
43 changes: 43 additions & 0 deletions test/test-ability-maker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/* globals describe: false, it:false, beforeEach:false, before:false */
'use strict';
const Roll20 = require('roll20-wrapper');
const expect = require('chai').expect;
const AbilityMaker = require('../lib/ability-maker');
const sinon = require('sinon');
const logger = require('./dummy-logger');
const Reporter = require('./dummy-reporter');
const cp = require('./dummy-command-parser');
const Roll20Object = require('./dummy-roll20-object');

describe('ability-maker', function () {
let roll20;

beforeEach(function () {
roll20 = new Roll20();
});


describe('ability creation', function () {
it('should create save ability', function () {
sinon.stub(roll20);
const characterStub = new Roll20Object('character');
characterStub.set('name', 'Bob');
const abilityStub = new Roll20Object('ability');
roll20.getOrCreateObj.withArgs('ability', {
characterid: characterStub.id,
name: 'Saves',
}).returns(abilityStub);
const abilityMaker = new AbilityMaker();
abilityMaker.configure(roll20, new Reporter(), logger, {}, cp);
abilityMaker.addAbility({
selected: { character: [characterStub] },
abilities: [abilityMaker.staticAbilityOptions.saves],
});

expect(roll20.getOrCreateObj.withArgs('ability', {
characterid: characterStub.id,
name: 'Saves',
}).callCount).to.equal(1);
});
});
});
29 changes: 0 additions & 29 deletions test/test-shaped-script.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,35 +58,6 @@ describe('shaped-script', function () {
});
});

describe('ability creation', function () {
it('should create save ability', function () {
sinon.stub(roll20);
const characterStub = new Roll20Object('character');
characterStub.set('name', 'Bob');
const tokenStub = new Roll20Object('graphic');
const abilityStub = new Roll20Object('ability');
tokenStub.set('represents', characterStub.id);
roll20.getObj.withArgs('graphic', tokenStub.id).returns(tokenStub);
roll20.getObj.withArgs('character', characterStub.id).returns(characterStub);
roll20.getOrCreateObj.withArgs('ability', {
characterid: characterStub.id,
name: 'Saves',
}).returns(abilityStub);
const reporter = new Reporter();
const shapedScript = new ShapedScripts(logger, { config: { updateAmmo: true } }, roll20, null,
el.entityLookup, reporter);
shapedScript.handleInput({
type: 'api',
content: '!shaped-abilities --saves',
selected: [{ _type: 'graphic', _id: tokenStub.id }],
});
expect(roll20.getOrCreateObj.withArgs('ability', {
characterid: characterStub.id,
name: 'Saves',
}).callCount).to.equal(1);
});
});

describe('handleSpellCast', function () {
it('should deal with cantrips correctly', function () {
const mock = sinon.mock(roll20);
Expand Down

0 comments on commit 88019de

Please sign in to comment.