|
|
|
|
@@ -1,118 +1,217 @@
|
|
|
|
|
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
|
|
|
|
import { migrateProperty } from './dbv1.js';
|
|
|
|
|
import { assert } from 'chai';
|
|
|
|
|
import {
|
|
|
|
|
migrateProperty
|
|
|
|
|
} from './dbv1.js';
|
|
|
|
|
import {
|
|
|
|
|
assert
|
|
|
|
|
} from 'chai';
|
|
|
|
|
import LibraryNodes from '/imports/api/library/LibraryNodes.js';
|
|
|
|
|
|
|
|
|
|
const exampleAction = {
|
|
|
|
|
'_id':'hY5MKZ4ivaoTRpNWy',
|
|
|
|
|
'actionType':'bonus',
|
|
|
|
|
'target':'singleTarget',
|
|
|
|
|
'tags':[],
|
|
|
|
|
'resources':{
|
|
|
|
|
'itemsConsumed':[],
|
|
|
|
|
'attributesConsumed':[{
|
|
|
|
|
'_id':'FaK6jXEj3pSe7mNuu',
|
|
|
|
|
'quantity': '1',
|
|
|
|
|
'variableName':'HunterTech',
|
|
|
|
|
'statName':'Hunter\'s Technique',
|
|
|
|
|
'available':5
|
|
|
|
|
}],
|
|
|
|
|
},
|
|
|
|
|
'type':'action',
|
|
|
|
|
'name':'Hexblade\\\'s Curse',
|
|
|
|
|
'parent':{
|
|
|
|
|
'id':'JqtDmqa5Zd3xpts5G',
|
|
|
|
|
'collection':'creatureProperties'
|
|
|
|
|
},
|
|
|
|
|
'ancestors':[
|
|
|
|
|
{
|
|
|
|
|
'collection':'creatures',
|
|
|
|
|
'id':'X9rzFhsgFhodYfHmG'
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
'order':315,
|
|
|
|
|
'summary':'Curse a creature for 1 minute. The curse ends early if {warlock.level >14 ? "" : "the target dies, or"} you are incapacitated. \nGain the following benefits: \n- *Bonus to damage rolls against the cursed target of* **+{proficiencyBonus}**. \n- Any attack roll you make against the cursed target is a **critical hit on a roll of 19 or 20**. \n- If the cursed target dies, you **regain {warlock.level+charisma.modifier} hit points**. \n{warlock.level <9 ? "" : "- If you are hit with an attack by your cursed target, use your reaction to roll a d6. On a 4 or higher, the attack instead misses."}',
|
|
|
|
|
'uses':'1',
|
|
|
|
|
'usesResult':1,
|
|
|
|
|
'reset':'shortRest',
|
|
|
|
|
'usesUsed':0,
|
|
|
|
|
'description':'Starting at 1st level, you gain the ability to place a baleful curse on someone. As a bonus action, choose one creature you can see within 30 feet of you. The target is cursed for 1 minute. The curse ends early if the target dies, you die, or you are incapacitated. Until the curse ends, you gain the following benefits:\n\n- You gain a bonus to damage rolls against the cursed target. The bonus equals your proficiency bonus.\n- Any attack roll you make against the cursed target is a critical hit on a roll of 19 or 20 on the d20.\n- If the cursed target dies, you regain hit points equal to your warlock level + your Charisma modifier (minimum of 1 hit point). \n{warlock.level <10 ? "" :"- If you are hit with an attack by your cursed target, use your reaction to roll a d6. On a 4 or higher, the attack instead misses."} \nYou can\\\'t use this feature again until you finish a short or long rest.',
|
|
|
|
|
'color':'#8e24aa',
|
|
|
|
|
'descriptionCalculations':[
|
|
|
|
|
{
|
|
|
|
|
'calculation':'warlock.level <10 ? "" :"- If you are hit with an attack by your cursed target, use your reaction to roll a d6. On a 4 or higher, the attack instead misses."',
|
|
|
|
|
'result':'- If you are hit with an attack by your cursed target, use your reaction to roll a d6. On a 4 or higher, the attack instead misses.'
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
'summaryCalculations':[
|
|
|
|
|
{
|
|
|
|
|
'calculation':'warlock.level >14 ? "" : "the target dies, or"',
|
|
|
|
|
'result':'the target dies, or'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
'calculation':'proficiencyBonus',
|
|
|
|
|
'result':'4'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
'calculation':'warlock.level+charisma.modifier',
|
|
|
|
|
'result':'15'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
'calculation':'warlock.level <9 ? "" : "- If you are hit with an attack by your cursed target, use your reaction to roll a d6. On a 4 or higher, the attack instead misses."',
|
|
|
|
|
'result':'- If you are hit with an attack by your cursed target, use your reaction to roll a d6. On a 4 or higher, the attack instead misses.'
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
'_id': 'hY5MKZ4ivaoTRpNWy',
|
|
|
|
|
'actionType': 'bonus',
|
|
|
|
|
'target': 'singleTarget',
|
|
|
|
|
'tags': [],
|
|
|
|
|
'resources': {
|
|
|
|
|
'itemsConsumed': [],
|
|
|
|
|
'attributesConsumed': [{
|
|
|
|
|
'_id': 'FaK6jXEj3pSe7mNuu',
|
|
|
|
|
'quantity': '1',
|
|
|
|
|
'variableName': 'HunterTech',
|
|
|
|
|
'statName': 'Hunter\'s Technique',
|
|
|
|
|
'available': 5
|
|
|
|
|
}],
|
|
|
|
|
},
|
|
|
|
|
'type': 'action',
|
|
|
|
|
'name': 'Hexblade\\\'s Curse',
|
|
|
|
|
'parent': {
|
|
|
|
|
'id': 'JqtDmqa5Zd3xpts5G',
|
|
|
|
|
'collection': 'creatureProperties'
|
|
|
|
|
},
|
|
|
|
|
'ancestors': [{
|
|
|
|
|
'collection': 'creatures',
|
|
|
|
|
'id': 'X9rzFhsgFhodYfHmG'
|
|
|
|
|
}, ],
|
|
|
|
|
'order': 315,
|
|
|
|
|
'summary': 'Curse a creature for 1 minute. The curse ends early if {warlock.level >14 ? "" : "the target dies, or"} you are incapacitated. \nGain the following benefits: \n- *Bonus to damage rolls against the cursed target of* **+{proficiencyBonus}**. \n- Any attack roll you make against the cursed target is a **critical hit on a roll of 19 or 20**. \n- If the cursed target dies, you **regain {warlock.level+charisma.modifier} hit points**. \n{warlock.level <9 ? "" : "- If you are hit with an attack by your cursed target, use your reaction to roll a d6. On a 4 or higher, the attack instead misses."}',
|
|
|
|
|
'uses': '1',
|
|
|
|
|
'usesResult': 1,
|
|
|
|
|
'reset': 'shortRest',
|
|
|
|
|
'usesUsed': 0,
|
|
|
|
|
'description': 'Starting at 1st level, you gain the ability to place a baleful curse on someone. As a bonus action, choose one creature you can see within 30 feet of you. The target is cursed for 1 minute. The curse ends early if the target dies, you die, or you are incapacitated. Until the curse ends, you gain the following benefits:\n\n- You gain a bonus to damage rolls against the cursed target. The bonus equals your proficiency bonus.\n- Any attack roll you make against the cursed target is a critical hit on a roll of 19 or 20 on the d20.\n- If the cursed target dies, you regain hit points equal to your warlock level + your Charisma modifier (minimum of 1 hit point). \n{warlock.level <10 ? "" :"- If you are hit with an attack by your cursed target, use your reaction to roll a d6. On a 4 or higher, the attack instead misses."} \nYou can\\\'t use this feature again until you finish a short or long rest.',
|
|
|
|
|
'color': '#8e24aa',
|
|
|
|
|
'descriptionCalculations': [{
|
|
|
|
|
'calculation': 'warlock.level <10 ? "" :"- If you are hit with an attack by your cursed target, use your reaction to roll a d6. On a 4 or higher, the attack instead misses."',
|
|
|
|
|
'result': '- If you are hit with an attack by your cursed target, use your reaction to roll a d6. On a 4 or higher, the attack instead misses.'
|
|
|
|
|
}],
|
|
|
|
|
'summaryCalculations': [{
|
|
|
|
|
'calculation': 'warlock.level >14 ? "" : "the target dies, or"',
|
|
|
|
|
'result': 'the target dies, or'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
'calculation': 'proficiencyBonus',
|
|
|
|
|
'result': '4'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
'calculation': 'warlock.level+charisma.modifier',
|
|
|
|
|
'result': '15'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
'calculation': 'warlock.level <9 ? "" : "- If you are hit with an attack by your cursed target, use your reaction to roll a d6. On a 4 or higher, the attack instead misses."',
|
|
|
|
|
'result': '- If you are hit with an attack by your cursed target, use your reaction to roll a d6. On a 4 or higher, the attack instead misses.'
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const exampleAttribute = {
|
|
|
|
|
_id:'idRWyoj5oxCv73feM',
|
|
|
|
|
name:'Hit Dice',
|
|
|
|
|
variableName:'clericHitDice',
|
|
|
|
|
attributeType:'hitDice',
|
|
|
|
|
type:'attribute',
|
|
|
|
|
hitDiceSize:'d8',
|
|
|
|
|
baseValueCalculation:'cleric.level',
|
|
|
|
|
parent:{'id':'8jSWKxvgQyKbunFtD','collection':'creatureProperties'},
|
|
|
|
|
ancestors:[
|
|
|
|
|
{'collection':'creatures','id':'m9sdCvs6iDf7qRaGv'},
|
|
|
|
|
{'id':'8jSWKxvgQyKbunFtD','collection':'creatureProperties'}
|
|
|
|
|
_id: 'idRWyoj5oxCv73feM',
|
|
|
|
|
name: 'Hit Dice',
|
|
|
|
|
variableName: 'clericHitDice',
|
|
|
|
|
attributeType: 'hitDice',
|
|
|
|
|
type: 'attribute',
|
|
|
|
|
hitDiceSize: 'd8',
|
|
|
|
|
baseValueCalculation: 'cleric.level',
|
|
|
|
|
parent: {
|
|
|
|
|
'id': '8jSWKxvgQyKbunFtD',
|
|
|
|
|
'collection': 'creatureProperties'
|
|
|
|
|
},
|
|
|
|
|
ancestors: [{
|
|
|
|
|
'collection': 'creatures',
|
|
|
|
|
'id': 'm9sdCvs6iDf7qRaGv'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
'id': '8jSWKxvgQyKbunFtD',
|
|
|
|
|
'collection': 'creatureProperties'
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
order: 84,
|
|
|
|
|
value: 20,
|
|
|
|
|
tags:[],
|
|
|
|
|
tags: [],
|
|
|
|
|
baseValue: 20,
|
|
|
|
|
damage: 3,
|
|
|
|
|
currentValue: 17,
|
|
|
|
|
constitutionMod: 2,
|
|
|
|
|
dependencies: ['8jSWKxvgQyKbunFtD','qPP5yQXPxS7uhuXo3']
|
|
|
|
|
dependencies: ['8jSWKxvgQyKbunFtD', 'qPP5yQXPxS7uhuXo3']
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const expectedMigratedAttribute = {
|
|
|
|
|
_id:'idRWyoj5oxCv73feM',
|
|
|
|
|
name:'Hit Dice',
|
|
|
|
|
variableName:'clericHitDice',
|
|
|
|
|
attributeType:'hitDice',
|
|
|
|
|
type:'attribute',
|
|
|
|
|
hitDiceSize:'d8',
|
|
|
|
|
_id: 'idRWyoj5oxCv73feM',
|
|
|
|
|
name: 'Hit Dice',
|
|
|
|
|
variableName: 'clericHitDice',
|
|
|
|
|
attributeType: 'hitDice',
|
|
|
|
|
type: 'attribute',
|
|
|
|
|
hitDiceSize: 'd8',
|
|
|
|
|
baseValue: {
|
|
|
|
|
calculation: 'cleric.level',
|
|
|
|
|
value: 20
|
|
|
|
|
},
|
|
|
|
|
parent:{'id':'8jSWKxvgQyKbunFtD','collection':'creatureProperties'},
|
|
|
|
|
ancestors:[
|
|
|
|
|
{'collection':'creatures','id':'m9sdCvs6iDf7qRaGv'},
|
|
|
|
|
{'id':'8jSWKxvgQyKbunFtD','collection':'creatureProperties'}
|
|
|
|
|
parent: {
|
|
|
|
|
'id': '8jSWKxvgQyKbunFtD',
|
|
|
|
|
'collection': 'creatureProperties'
|
|
|
|
|
},
|
|
|
|
|
ancestors: [{
|
|
|
|
|
'collection': 'creatures',
|
|
|
|
|
'id': 'm9sdCvs6iDf7qRaGv'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
'id': '8jSWKxvgQyKbunFtD',
|
|
|
|
|
'collection': 'creatureProperties'
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
order: 84,
|
|
|
|
|
total: 20,
|
|
|
|
|
tags:[],
|
|
|
|
|
tags: [],
|
|
|
|
|
damage: 3,
|
|
|
|
|
value: 17,
|
|
|
|
|
constitutionMod: 2,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
describe('migrateProperty', function () {
|
|
|
|
|
it('Migrates actions reversibly', function () {
|
|
|
|
|
const action = {...exampleAction};
|
|
|
|
|
const exampleAttack = {
|
|
|
|
|
'_id': 'vw23EnJwBRcXEJg7i',
|
|
|
|
|
'actionType': 'attack',
|
|
|
|
|
'target': 'singleTarget',
|
|
|
|
|
'tags': ['attack'],
|
|
|
|
|
'results': {
|
|
|
|
|
'adjustments': [],
|
|
|
|
|
'damages': [{
|
|
|
|
|
'_id': 'RGJMeNJXBeqZsGmAw',
|
|
|
|
|
'damage': '1d4 + strength.modifier',
|
|
|
|
|
'target': 'every',
|
|
|
|
|
'damageType': 'slashing'
|
|
|
|
|
}],
|
|
|
|
|
'buffs': []
|
|
|
|
|
},
|
|
|
|
|
'resources': {
|
|
|
|
|
'itemsConsumed': [],
|
|
|
|
|
'attributesConsumed': []
|
|
|
|
|
},
|
|
|
|
|
'rollBonus': 'dexterity.modifier + proficiencyBonus + 2 - hp.value + hp.currentValue',
|
|
|
|
|
'type': 'attack',
|
|
|
|
|
'name': 'Claws',
|
|
|
|
|
'parent': {
|
|
|
|
|
'id': 'Jpx8q3WjM5SCoGBm8',
|
|
|
|
|
'collection': 'creatureProperties'
|
|
|
|
|
},
|
|
|
|
|
'ancestors': [{
|
|
|
|
|
'collection': 'creatures',
|
|
|
|
|
'id': 'm9sdCvs6iDf7qRaGv'
|
|
|
|
|
}, {
|
|
|
|
|
'id': '3WS2xsSPAqB4eF9YH',
|
|
|
|
|
'collection': 'creatureProperties'
|
|
|
|
|
}, {
|
|
|
|
|
'id': 'rhYLEycvtHjcioaQL',
|
|
|
|
|
'collection': 'creatureProperties'
|
|
|
|
|
}, {
|
|
|
|
|
'id': 'Jpx8q3WjM5SCoGBm8',
|
|
|
|
|
'collection': 'creatureProperties'
|
|
|
|
|
}],
|
|
|
|
|
'order': 56,
|
|
|
|
|
'rollBonusResult': 6,
|
|
|
|
|
'usesUsed': 2,
|
|
|
|
|
'dependencies': ['pg6cK5ghHTFvo8uyK', 'gAJBKYqXz2BPc9Aqf']
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const expectedMigratedAttack = {
|
|
|
|
|
'_id': 'vw23EnJwBRcXEJg7i',
|
|
|
|
|
'actionType': 'attack',
|
|
|
|
|
'target': 'singleTarget',
|
|
|
|
|
'tags': ['attack'],
|
|
|
|
|
'resources': {
|
|
|
|
|
'itemsConsumed': [],
|
|
|
|
|
'attributesConsumed': []
|
|
|
|
|
},
|
|
|
|
|
'attackRoll': {
|
|
|
|
|
calculation: 'dexterity.modifier + proficiencyBonus + 2 - hp.total + hp.value',
|
|
|
|
|
},
|
|
|
|
|
'type': 'action',
|
|
|
|
|
'name': 'Claws',
|
|
|
|
|
'parent': {
|
|
|
|
|
'id': 'Jpx8q3WjM5SCoGBm8',
|
|
|
|
|
'collection': 'creatureProperties'
|
|
|
|
|
},
|
|
|
|
|
'ancestors': [{
|
|
|
|
|
'collection': 'creatures',
|
|
|
|
|
'id': 'm9sdCvs6iDf7qRaGv'
|
|
|
|
|
}, {
|
|
|
|
|
'id': '3WS2xsSPAqB4eF9YH',
|
|
|
|
|
'collection': 'creatureProperties'
|
|
|
|
|
}, {
|
|
|
|
|
'id': 'rhYLEycvtHjcioaQL',
|
|
|
|
|
'collection': 'creatureProperties'
|
|
|
|
|
}, {
|
|
|
|
|
'id': 'Jpx8q3WjM5SCoGBm8',
|
|
|
|
|
'collection': 'creatureProperties'
|
|
|
|
|
}],
|
|
|
|
|
'order': 56,
|
|
|
|
|
'usesUsed': 2,
|
|
|
|
|
libraryTags: [],
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
describe('migrateProperty', function() {
|
|
|
|
|
it('Migrates actions reversibly', function() {
|
|
|
|
|
const action = {
|
|
|
|
|
...exampleAction
|
|
|
|
|
};
|
|
|
|
|
const newAction = migrateProperty({
|
|
|
|
|
collection: CreatureProperties,
|
|
|
|
|
prop: action
|
|
|
|
|
@@ -125,8 +224,10 @@ describe('migrateProperty', function () {
|
|
|
|
|
assert.deepEqual(action, exampleAction, 'action should not be bashed');
|
|
|
|
|
assert.deepEqual(exampleAction, reversedAction, 'operation should be reversible');
|
|
|
|
|
});
|
|
|
|
|
it ('Migrates attributes as expected', function(){
|
|
|
|
|
const attribute = {...exampleAttribute};
|
|
|
|
|
it('Migrates attributes as expected', function() {
|
|
|
|
|
const attribute = {
|
|
|
|
|
...exampleAttribute
|
|
|
|
|
};
|
|
|
|
|
const newAttribute = migrateProperty({
|
|
|
|
|
collection: CreatureProperties,
|
|
|
|
|
prop: attribute
|
|
|
|
|
@@ -134,4 +235,15 @@ describe('migrateProperty', function () {
|
|
|
|
|
assert.deepEqual(newAttribute, expectedMigratedAttribute,
|
|
|
|
|
'Attribute should match the expected result');
|
|
|
|
|
});
|
|
|
|
|
it('Migrates attacks as expected', function() {
|
|
|
|
|
const attribute = {
|
|
|
|
|
...exampleAttack
|
|
|
|
|
};
|
|
|
|
|
const newAttribute = migrateProperty({
|
|
|
|
|
collection: LibraryNodes,
|
|
|
|
|
prop: attribute
|
|
|
|
|
});
|
|
|
|
|
assert.deepEqual(newAttribute, expectedMigratedAttack,
|
|
|
|
|
'Attribute should match the expected result');
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|