mirror of
https://github.com/sudoxnym/habitica.git
synced 2026-05-22 05:38:46 +00:00
Merge branch 'release' into develop
This commit is contained in:
commit
3063a38d60
4 changed files with 135 additions and 16 deletions
2
package-lock.json
generated
2
package-lock.json
generated
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "habitica",
|
||||
"version": "4.144.0",
|
||||
"version": "4.144.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "habitica",
|
||||
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
|
||||
"version": "4.144.0",
|
||||
"version": "4.144.1",
|
||||
"main": "./website/server/index.js",
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.10.2",
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ describe('shared.ops.unlock', () => {
|
|||
const unlockGearSetPath = 'items.gear.owned.headAccessory_special_bearEars,items.gear.owned.headAccessory_special_cactusEars,items.gear.owned.headAccessory_special_foxEars,items.gear.owned.headAccessory_special_lionEars,items.gear.owned.headAccessory_special_pandaEars,items.gear.owned.headAccessory_special_pigEars,items.gear.owned.headAccessory_special_tigerEars,items.gear.owned.headAccessory_special_wolfEars';
|
||||
const backgroundUnlockPath = 'background.giant_florals';
|
||||
const backgroundSetUnlockPath = 'background.archery_range,background.giant_florals,background.rainbows_end';
|
||||
const hairUnlockPath = 'hair.color.rainbow,hair.color.yellow,hair.color.green,hair.color.purple,hair.color.blue,hair.color.TRUred';
|
||||
const facialHairUnlockPath = 'hair.mustache.1,hair.mustache.2,hair.beard.1,hair.beard.2,hair.beard.3';
|
||||
const usersStartingGems = 50 / 4;
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
@ -206,6 +208,40 @@ describe('shared.ops.unlock', () => {
|
|||
expect(user.balance).to.equal(usersStartingGems - 1.25);
|
||||
});
|
||||
|
||||
it('unlocks a full set of hair items', () => {
|
||||
user.purchased.hair.color = {};
|
||||
|
||||
const initialHairColors = Object.keys(user.purchased.hair.color).length;
|
||||
const [, message] = unlock(user, { query: { path: hairUnlockPath } });
|
||||
|
||||
expect(message).to.equal(i18n.t('unlocked'));
|
||||
const individualPaths = hairUnlockPath.split(',');
|
||||
individualPaths.forEach(path => {
|
||||
expect(get(user.purchased, path)).to.be.true;
|
||||
});
|
||||
expect(Object.keys(user.purchased.hair.color).length)
|
||||
.to.equal(initialHairColors + individualPaths.length);
|
||||
expect(user.balance).to.equal(usersStartingGems - 1.25);
|
||||
});
|
||||
|
||||
it('unlocks the facial hair set', () => {
|
||||
user.purchased.hair.mustache = {};
|
||||
user.purchased.hair.beard = {};
|
||||
|
||||
const initialMustache = Object.keys(user.purchased.hair.mustache).length;
|
||||
const initialBeard = Object.keys(user.purchased.hair.mustache).length;
|
||||
const [, message] = unlock(user, { query: { path: facialHairUnlockPath } });
|
||||
|
||||
expect(message).to.equal(i18n.t('unlocked'));
|
||||
const individualPaths = facialHairUnlockPath.split(',');
|
||||
individualPaths.forEach(path => {
|
||||
expect(get(user.purchased, path)).to.be.true;
|
||||
});
|
||||
expect(Object.keys(user.purchased.hair.mustache).length + Object.keys(user.purchased.hair.beard).length) // eslint-disable-line max-len
|
||||
.to.equal(initialMustache + initialBeard + individualPaths.length);
|
||||
expect(user.balance).to.equal(usersStartingGems - 1.25);
|
||||
});
|
||||
|
||||
it('unlocks a full set of gear', () => {
|
||||
const initialGear = Object.keys(user.items.gear.owned).length;
|
||||
const [, message] = unlock(user, { query: { path: unlockGearSetPath } });
|
||||
|
|
@ -246,6 +282,37 @@ describe('shared.ops.unlock', () => {
|
|||
expect(user.balance).to.equal(usersStartingGems - 0.5);
|
||||
});
|
||||
|
||||
it('unlocks an item (hair color)', () => {
|
||||
user.purchased.hair.color = {};
|
||||
|
||||
const path = hairUnlockPath.split(',')[0];
|
||||
const initialColorHair = Object.keys(user.purchased.hair.color).length;
|
||||
const [, message] = unlock(user, { query: { path } });
|
||||
|
||||
expect(message).to.equal(i18n.t('unlocked'));
|
||||
expect(Object.keys(user.purchased.hair.color).length).to.equal(initialColorHair + 1);
|
||||
expect(get(user.purchased, path)).to.be.true;
|
||||
expect(user.balance).to.equal(usersStartingGems - 0.5);
|
||||
});
|
||||
|
||||
it('unlocks an item (facial hair)', () => {
|
||||
user.purchased.hair.mustache = {};
|
||||
user.purchased.hair.beard = {};
|
||||
|
||||
const path = facialHairUnlockPath.split(',')[0];
|
||||
const initialMustache = Object.keys(user.purchased.hair.mustache).length;
|
||||
const initialBeard = Object.keys(user.purchased.hair.beard).length;
|
||||
const [, message] = unlock(user, { query: { path } });
|
||||
|
||||
expect(message).to.equal(i18n.t('unlocked'));
|
||||
|
||||
expect(Object.keys(user.purchased.hair.mustache).length).to.equal(initialMustache + 1);
|
||||
expect(Object.keys(user.purchased.hair.beard).length).to.equal(initialBeard);
|
||||
|
||||
expect(get(user.purchased, path)).to.be.true;
|
||||
expect(user.balance).to.equal(usersStartingGems - 0.5);
|
||||
});
|
||||
|
||||
it('unlocks an item (gear)', () => {
|
||||
const path = unlockGearSetPath.split(',')[0];
|
||||
const initialGear = Object.keys(user.items.gear.owned).length;
|
||||
|
|
|
|||
|
|
@ -28,12 +28,16 @@ function invalidSet (req) {
|
|||
* Return an item given its path and the type of set
|
||||
*/
|
||||
function getItemByPath (path, setType) {
|
||||
const itemKey = splitPathItem(path)[1];
|
||||
const item = setType === 'gear'
|
||||
? content.gear.flat[itemKey]
|
||||
: content.appearances[setType][itemKey];
|
||||
const [itemPathParent, itemKey] = splitPathItem(path);
|
||||
|
||||
return item;
|
||||
if (setType === 'gear') return content.gear.flat[itemKey];
|
||||
if (setType === 'hair') {
|
||||
// itemPathParent is in this format: hair.purple
|
||||
const hairType = itemPathParent.split('.')[1];
|
||||
return content.appearances.hair[hairType][itemKey];
|
||||
}
|
||||
|
||||
return content.appearances[setType][itemKey];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -48,6 +52,25 @@ function getSetType (firstPath, req) {
|
|||
return invalidSet(req);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the items and paths for a set given the set,
|
||||
* a list of items of the type and a prefix for the path.
|
||||
*/
|
||||
function getItemsAndPathsForSet (set, itemsCollection, pathPrefix) {
|
||||
const items = [];
|
||||
const paths = [];
|
||||
|
||||
Object.keys(itemsCollection).forEach(possibleItemKey => {
|
||||
const possibleItem = itemsCollection[possibleItemKey];
|
||||
if (possibleItem && possibleItem.set && possibleItem.set.key === set.key) {
|
||||
items.push(possibleItem);
|
||||
paths.push(`${pathPrefix}.${possibleItem.key}`);
|
||||
}
|
||||
});
|
||||
|
||||
return { items, paths };
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the set of items to unlock given the path of the first item in the set.
|
||||
*/
|
||||
|
|
@ -78,16 +101,45 @@ function getSet (setType, firstPath, req) {
|
|||
const { set } = item;
|
||||
if (!set || set.setPrice === 0) return invalidSet(req);
|
||||
|
||||
const items = [];
|
||||
const paths = [];
|
||||
// The facialHair set is split between hair.mustache and hair.beards
|
||||
if (setType === 'hair' && set.key === 'facialHair') {
|
||||
const items = [];
|
||||
const paths = [];
|
||||
|
||||
Object.keys(content.appearances[setType]).forEach(possibleItemKey => {
|
||||
const possibleItem = content.appearances[setType][possibleItemKey];
|
||||
if (possibleItem && possibleItem.set && possibleItem.set.key === set.key) {
|
||||
items.push(possibleItem);
|
||||
paths.push(`${setType}.${possibleItem.key}`);
|
||||
}
|
||||
});
|
||||
const { mustache } = content.appearances.hair;
|
||||
const mustachePrefix = 'hair.mustache';
|
||||
|
||||
const {
|
||||
items: mustacheItems,
|
||||
paths: mustachePaths,
|
||||
} = getItemsAndPathsForSet(set, mustache, mustachePrefix);
|
||||
|
||||
|
||||
const { beard } = content.appearances.hair;
|
||||
const beardPrefix = 'hair.beard';
|
||||
|
||||
const {
|
||||
items: beardItems,
|
||||
paths: beardPaths,
|
||||
} = getItemsAndPathsForSet(set, beard, beardPrefix);
|
||||
|
||||
items.push(...beardItems, ...mustacheItems);
|
||||
paths.push(...beardPaths, ...mustachePaths);
|
||||
|
||||
return { items, paths, set };
|
||||
}
|
||||
|
||||
let pathPrefix = setType;
|
||||
let itemsCollection = content.appearances[setType];
|
||||
|
||||
if (setType === 'hair') { // hair sets are nested like hair.color.item
|
||||
const nestedSet = firstPath.split('.')[1];
|
||||
|
||||
itemsCollection = itemsCollection[nestedSet];
|
||||
pathPrefix = `${pathPrefix}.${nestedSet}`;
|
||||
}
|
||||
|
||||
const { items, paths } = getItemsAndPathsForSet(set, itemsCollection, pathPrefix);
|
||||
|
||||
return { items, paths, set };
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue