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:
@@ -253,6 +253,10 @@
|
||||
"questEggDolphinMountText": "Dolphin",
|
||||
"questEggDolphinAdjective": "a chipper",
|
||||
|
||||
"questEggRobotText": "Robot",
|
||||
"questEggRobotMountText": "Robot",
|
||||
"questEggRobotAdjective": "a futuristic",
|
||||
|
||||
"eggNotes": "Find a hatching potion to pour on this egg, and it will hatch into <%= eggAdjective(locale) %> <%= eggText(locale) %>.",
|
||||
|
||||
"hatchingPotionBase": "Base",
|
||||
|
||||
@@ -763,5 +763,14 @@
|
||||
"questSilverCollectMoonRunes": "Moon Runes",
|
||||
"questSilverCollectSilverIngots": "Silver Ingots",
|
||||
"questSilverDropSilverPotion": "Silver Hatching Potion",
|
||||
"questSilverUnlockText": "Unlocks purchasable Silver hatching potions in the Market"
|
||||
"questSilverUnlockText": "Unlocks purchasable Silver hatching potions in the Market",
|
||||
|
||||
"questRobotText": "Mysterious Mechanical Marvels!",
|
||||
"questRobotNotes": "At Max Capacity labs, @Rev is putting the finishing touches on their newest invention, a robotic Accountability Buddy, when a strange metal vehicle suddenly appears in a plume of smoke, inches from the robot’s Fluctuation Detector! Its occupants, two strange figures dressed in silver, emerge and remove their space helmets, revealing themselves as @FolleMente and @McCoyly.<br><br>“I hypothesize that there was an anomaly in our productivity implementation,” @FolleMente says sheepishly.<br><br>@McCoyly crosses her arms. “That means they neglected to complete their Dailies, which I postulate led to the disintegration of our Productivity Stabilizer. It’s an essential component to time travel that needs consistency to work properly. Our accomplishments power our movement through time and space! I don’t have time to explain further, @Rev. You’ll discover it in 37 years, or perhaps your allies the Mysterious Time Travelers can fill you in. For now, can you help us fix our time machine?”",
|
||||
"questRobotCompletion": "As @Rev and the Accountability Buddy place the last bolt in place, the time machine buzzes to life. @FolleMente and @McCoyly jump aboard. “Thanks for the assist! We’ll see you in the future! By the way, these should help you with your next invention!” With that, the time travelers disappear, but left behind in the wreckage of the old Productivity Stabilizer are three clockwork eggs. Perhaps these will be the crucial components for a new production line of Accountability Buddies!",
|
||||
"questRobotCollectBolts": "Bolts",
|
||||
"questRobotCollectGears": "Gears",
|
||||
"questRobotCollectSprings": "Springs",
|
||||
"questRobotDropRobotEgg": "Robot (Egg)",
|
||||
"questRobotUnlockText": "Unlocks purchasable Robot Eggs in the Market"
|
||||
}
|
||||
|
||||
@@ -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, {
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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':
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user