Hourglass Quest (#11325)

* feat(content): Hourglass Quest

* fix(hourglasses): NaN from undefined

* fix(quests): sanity check for negative scrolls

* fix(hourglasses): don't show quantity selection for binary items

* fix(route): validate number, use body not params

* test(timetrav): add quest tests
This commit is contained in:
Sabe Jones
2019-08-29 15:22:12 -04:00
committed by GitHub
parent 9077290ea3
commit fc841d0ad4
61 changed files with 209 additions and 42 deletions
+6
View File
@@ -386,6 +386,12 @@ let quests = {
adjective: t('questEggDolphinAdjective'),
canBuy: hasQuestAchievementFunction('dolphin'),
},
Robot: {
text: t('questEggRobotText'),
mountText: t('questEggRobotMountText'),
adjective: t('questEggRobotAdjective'),
canBuy: hasQuestAchievementFunction('robot'),
},
};
applyEggDefaults(drops, {
+44
View File
@@ -3458,6 +3458,50 @@ let quests = {
unlock: t('questSilverUnlockText'),
},
},
robot: {
text: t('questRobotText'),
notes: t('questRobotNotes'),
completion: t('questRobotCompletion'),
value: 1,
category: 'timeTravelers',
canBuy () {
return false;
},
collect: {
bolt: {
text: t('questRobotCollectBolts'),
count: 15,
},
gear: {
text: t('questRobotCollectGears'),
count: 10,
},
spring: {
text: t('questRobotCollectSprings'),
count: 10,
},
},
drop: {
items: [
{
type: 'eggs',
key: 'Robot',
text: t('questRobotDropRobotEgg'),
}, {
type: 'eggs',
key: 'Robot',
text: t('questRobotDropRobotEgg'),
}, {
type: 'eggs',
key: 'Robot',
text: t('questRobotDropRobotEgg'),
},
],
gp: 40,
exp: 75,
unlock: t('questRobotUnlockText'),
},
},
};
each(quests, (v, key) => {
+7 -1
View File
@@ -132,7 +132,6 @@ module.exports = function getItemInfo (user, type, item, officialPinnedItems, la
notes: item.notes(language),
group: item.group,
value: item.goldValue ? item.goldValue : item.value,
currency: item.goldValue ? 'gold' : 'gems',
locked,
previous: content.quests[item.previous] ? content.quests[item.previous].text(language) : null,
unlockCondition: item.unlockCondition,
@@ -150,6 +149,13 @@ module.exports = function getItemInfo (user, type, item, officialPinnedItems, la
path: `quests.${item.key}`,
pinType: 'quests',
};
if (item.goldValue) {
itemInfo.currency = 'gold';
} else if (item.category === 'timeTravelers') {
itemInfo.currency = 'hourglasses';
} else {
itemInfo.currency = 'gems';
}
break;
case 'timeTravelers':
+14
View File
@@ -333,6 +333,20 @@ shops.getTimeTravelersCategories = function getTimeTravelersCategories (user, la
let stable = {pets: 'Pet-', mounts: 'Mount_Icon_'};
let officialPinnedItems = getOfficialPinnedItems(user);
let questCategory = {
identifier: 'quests',
text: i18n.t('quests', language),
items: [],
};
for (let key in content.quests) {
if (content.quests[key].category === 'timeTravelers') {
let item = getItemInfo(user, 'quests', content.quests[key], officialPinnedItems, language);
questCategory.items.push(item);
}
}
categories.push(questCategory);
for (let type in stable) {
if (stable.hasOwnProperty(type)) {
let category = {
+9 -3
View File
@@ -19,8 +19,10 @@ import {BuyQuestWithGemOperation} from './buyQuestGem';
// @TODO: when we are sure buy is the only function used, let's move the buy files to a folder
module.exports = function buy (user, req = {}, analytics) {
module.exports = function buy (user, req = {}, analytics, options = {quantity: 1, hourglass: false}) {
let key = get(req, 'params.key');
const hourglass = options.hourglass;
const quantity = options.quantity;
if (!key) throw new BadRequest(errorMessage('missingKeyParam'));
// @TODO: Slowly remove the need for key and use type instead
@@ -54,9 +56,13 @@ module.exports = function buy (user, req = {}, analytics) {
break;
}
case 'quests': {
const buyOp = new BuyQuestWithGemOperation(user, req, analytics);
if (hourglass) {
buyRes = hourglassPurchase(user, req, analytics, quantity);
} else {
const buyOp = new BuyQuestWithGemOperation(user, req, analytics);
buyRes = buyOp.purchase();
buyRes = buyOp.purchase();
}
break;
}
case 'eggs':
@@ -9,39 +9,52 @@ import {
} from '../../libs/errors';
import errorMessage from '../../libs/errorMessage';
module.exports = function purchaseHourglass (user, req = {}, analytics) {
module.exports = function purchaseHourglass (user, req = {}, analytics, quantity = 1) {
let key = get(req, 'params.key');
if (!key) throw new BadRequest(errorMessage('missingKeyParam'));
let type = get(req, 'params.type');
if (!type) throw new BadRequest(errorMessage('missingTypeParam'));
if (!content.timeTravelStable[type]) {
throw new NotAuthorized(i18n.t('typeNotAllowedHourglass', {allowedTypes: keys(content.timeTravelStable).toString()}, req.language));
}
if (type === 'quests') {
if (!content.quests[key] || content.quests[key].category !== 'timeTravelers') throw new NotAuthorized(i18n.t('notAllowedHourglass', req.language));
if (user.purchased.plan.consecutive.trinkets < quantity) {
throw new NotAuthorized(i18n.t('notEnoughHourglasses', req.language));
}
if (!includes(keys(content.timeTravelStable[type]), key)) {
throw new NotAuthorized(i18n.t('notAllowedHourglass', req.language));
}
if (!user.items.quests[key] || user.items.quests[key] < 0) user.items.quests[key] = 0;
user.items.quests[key] += quantity;
user.purchased.plan.consecutive.trinkets -= quantity;
if (user.items[type][key]) {
throw new NotAuthorized(i18n.t(`${type}AlreadyOwned`, req.language));
}
if (user.markModified) user.markModified('items.quests');
} else {
if (!content.timeTravelStable[type]) {
throw new NotAuthorized(i18n.t('typeNotAllowedHourglass', {allowedTypes: keys(content.timeTravelStable).toString()}, req.language));
}
if (user.purchased.plan.consecutive.trinkets <= 0) {
throw new NotAuthorized(i18n.t('notEnoughHourglasses', req.language));
}
if (!includes(keys(content.timeTravelStable[type]), key)) {
throw new NotAuthorized(i18n.t('notAllowedHourglass', req.language));
}
user.purchased.plan.consecutive.trinkets--;
if (user.items[type][key]) {
throw new NotAuthorized(i18n.t(`${type}AlreadyOwned`, req.language));
}
if (type === 'pets') {
user.items.pets[key] = 5;
if (user.markModified) user.markModified('items.pets');
}
if (user.purchased.plan.consecutive.trinkets <= 0) {
throw new NotAuthorized(i18n.t('notEnoughHourglasses', req.language));
}
if (type === 'mounts') {
user.items.mounts[key] = true;
if (user.markModified) user.markModified('items.mounts');
user.purchased.plan.consecutive.trinkets--;
if (type === 'pets') {
user.items.pets[key] = 5;
if (user.markModified) user.markModified('items.pets');
}
if (type === 'mounts') {
user.items.mounts[key] = true;
if (user.markModified) user.markModified('items.mounts');
}
}
if (analytics) {