From 692d02984b509b2f350a677d643f9460c6405058 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Tue, 9 Jun 2020 22:13:22 +0200 Subject: [PATCH 1/2] unlock: fix unlocking hair items --- test/common/ops/unlock.js | 67 ++++++++++++++++++++++++ website/common/script/ops/unlock.js | 80 ++++++++++++++++++++++++----- 2 files changed, 133 insertions(+), 14 deletions(-) diff --git a/test/common/ops/unlock.js b/test/common/ops/unlock.js index baf1408515..b6307e59c3 100644 --- a/test/common/ops/unlock.js +++ b/test/common/ops/unlock.js @@ -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; diff --git a/website/common/script/ops/unlock.js b/website/common/script/ops/unlock.js index da2dd78baf..46b63bf92d 100644 --- a/website/common/script/ops/unlock.js +++ b/website/common/script/ops/unlock.js @@ -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 }; } From 51d20ef7e85aa612a880ebfc1bf6f1524759db90 Mon Sep 17 00:00:00 2001 From: Sabe Jones Date: Tue, 9 Jun 2020 15:27:43 -0500 Subject: [PATCH 2/2] 4.144.1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index aaec2d9561..2154867ac0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "habitica", - "version": "4.144.0", + "version": "4.144.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index bbbd02945b..eee650c6eb 100644 --- a/package.json +++ b/package.json @@ -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",