diff --git a/common/locales/en/messages.json b/common/locales/en/messages.json index bf23a6363c..70c65c7b62 100644 --- a/common/locales/en/messages.json +++ b/common/locales/en/messages.json @@ -5,6 +5,7 @@ "messageTagNotFound": "Tag not found.", "messagePetNotFound": ":pet not found in user.items.pets", "messageFoodNotFound": ":food not found in user.items.food", + "messageNotAvailable": "This item is not currently available for purchase.", "messageCannotFeedPet": "Can't feed this pet.", "messageAlreadyMount": "You already have that mount. Try feeding another pet.", "messageEvolve": "You have tamed <%= egg %>, let's go for a ride!", @@ -14,6 +15,7 @@ "messageEquipped": " <%= itemText %> equipped.", "messageUnEquipped": "<%= itemText %> un-equipped.", "messageMissingEggPotion": "You're missing either that egg or that potion", + "messageInvalidEggPotionCombo": "Invalid egg+potion combination. Try hatching a different egg!", "messageAlreadyPet": "You already have that pet. Try hatching a different combination!", "messageHatched": "Your egg hatched! Visit your stable to equip your pet.", "messageNotEnoughGold": "Not Enough Gold", diff --git a/common/script/index.coffee b/common/script/index.coffee index 3672e584e1..d25ad683a2 100644 --- a/common/script/index.coffee +++ b/common/script/index.coffee @@ -822,7 +822,8 @@ api.wrap = (user, main=true) -> item = content[type][key] price = item.value / 4 return cb?({code:404,message:":key not found for Content.#{type}"},req) unless item - return cb?({code:401, message: i18n.t('notEnoughGems', req.language)}) if (user.balance < price) or !user.balance + return cb?({code:403, message: i18n.t('messageNotAvailable', req.language)}) if type is 'hatchingPotions' and not item.canBuy + return cb?({code:403, message: i18n.t('notEnoughGems', req.language)}) if (user.balance < price) or !user.balance user.balance -= price if type is 'gear' then user.items.gear.owned[key] = true else @@ -1070,10 +1071,11 @@ api.wrap = (user, main=true) -> hatch: (req, cb) -> {egg, hatchingPotion} = req.params - return cb?({code:404,message:"Please specify query.egg & query.hatchingPotion"}) unless egg and hatchingPotion - return cb?({code:401,message:i18n.t('messageMissingEggPotion', req.language)}) unless user.items.eggs[egg] > 0 and user.items.hatchingPotions[hatchingPotion] > 0 + return cb?({code:400,message:"Please specify query.egg & query.hatchingPotion"}) unless egg and hatchingPotion + return cb?({code:403,message:i18n.t('messageMissingEggPotion', req.language)}) unless user.items.eggs[egg] > 0 and user.items.hatchingPotions[hatchingPotion] > 0 + return cb?({code:403,message:i18n.t('messageInvalidEggPotionCombo', req.language)}) if content.hatchingPotions[hatchingPotion].premium and not content.dropEggs[egg] pet = "#{egg}-#{hatchingPotion}" - return cb?({code:401, message:i18n.t('messageAlreadyPet', req.language)}) if user.items.pets[pet] and user.items.pets[pet] > 0 + return cb?({code:403, message:i18n.t('messageAlreadyPet', req.language)}) if user.items.pets[pet] and user.items.pets[pet] > 0 user.items.pets[pet] = 5 user.items.eggs[egg]-- user.items.hatchingPotions[hatchingPotion]-- diff --git a/test/common/user.ops.hatch.js b/test/common/user.ops.hatch.js new file mode 100644 index 0000000000..2ec1d627d3 --- /dev/null +++ b/test/common/user.ops.hatch.js @@ -0,0 +1,139 @@ +var sinon = require('sinon'); +var chai = require('chai'); +chai.use(require('sinon-chai')) +var expect = chai.expect + +require('coffee-script'); +var shared = require('../../common/script/index.coffee'); +var content = require('../../common/script/content/index.coffee'); + +describe('user.ops.hatch', function() { + var user; + + beforeEach(function() { + user = { + items: { + eggs: {}, + hatchingPotions: {}, + pets: {} + } + }; + + shared.wrap(user); + }); + + context('Pet Hatching', function() { + + context('failure conditions', function() { + + it('does not allow hatching without specifying egg and potion', function(done) { + user.ops.hatch({params:{}},function(response) { + expect(response.message).to.eql('Please specify query.egg & query.hatchingPotion'); + expect(user.items.pets).to.be.empty; + done(); + }); + }); + + it('does not allow hatching if user lacks specified egg', function(done) { + user.items.eggs = {'Wolf':1}; + user.items.hatchingPotions = {'Base':1}; + user.ops.hatch({params:{egg:'Dragon',hatchingPotion:'Base'}}, function(response) { + expect(response.message).to.eql(shared.i18n.t('messageMissingEggPotion')); + expect(user.items.pets).to.be.empty; + expect(user.items.eggs).to.eql({'Wolf':1}); + expect(user.items.hatchingPotions).to.eql({'Base':1}); + done(); + }); + }); + + it('does not allow hatching if user lacks specified hatching potion', function(done) { + user.items.eggs = {'Wolf':1}; + user.items.hatchingPotions = {'Base':1}; + user.ops.hatch({params:{egg:'Wolf',hatchingPotion:'Golden'}}, function(response) { + expect(response.message).to.eql(shared.i18n.t('messageMissingEggPotion')); + expect(user.items.pets).to.be.empty; + expect(user.items.eggs).to.eql({'Wolf':1}); + expect(user.items.hatchingPotions).to.eql({'Base':1}); + done(); + }); + }); + + it('does not allow hatching if user already owns target pet', function(done) { + user.items.eggs = {'Wolf':1}; + user.items.hatchingPotions = {'Base':1}; + user.items.pets = {'Wolf-Base':10}; + user.ops.hatch({params:{egg:'Wolf',hatchingPotion:'Base'}}, function(response) { + expect(response.message).to.eql(shared.i18n.t('messageAlreadyPet')); + expect(user.items.pets).to.eql({'Wolf-Base':10}); + expect(user.items.eggs).to.eql({'Wolf':1}); + expect(user.items.hatchingPotions).to.eql({'Base':1}); + done(); + }); + }); + + it('does not allow hatching quest pet egg using premium potion', function(done) { + user.items.eggs = {'Cheetah':1}; + user.items.hatchingPotions = {'Spooky':1}; + user.ops.hatch({params:{egg:'Cheetah',hatchingPotion:'Spooky'}}, function(response) { + expect(response.message).to.eql(shared.i18n.t('messageInvalidEggPotionCombo')); + expect(user.items.pets).to.be.empty; + expect(user.items.eggs).to.eql({'Cheetah':1}); + expect(user.items.hatchingPotions).to.eql({'Spooky':1}); + done(); + }); + }); + }); + + context('successful hatching', function() { + + it('hatches a basic pet', function(done) { + user.items.eggs = {'Wolf':1}; + user.items.hatchingPotions = {'Base':1}; + user.ops.hatch({params:{egg:'Wolf',hatchingPotion:'Base'}}, function(response) { + expect(response.message).to.eql(shared.i18n.t('messageHatched')); + expect(user.items.pets).to.eql({'Wolf-Base':5}); + expect(user.items.eggs).to.eql({'Wolf':0}); + expect(user.items.hatchingPotions).to.eql({'Base':0}); + done(); + }); + }); + + it('hatches a quest pet', function(done) { + user.items.eggs = {'Cheetah':1}; + user.items.hatchingPotions = {'Base':1}; + user.ops.hatch({params:{egg:'Cheetah',hatchingPotion:'Base'}}, function(response) { + expect(response.message).to.eql(shared.i18n.t('messageHatched')); + expect(user.items.pets).to.eql({'Cheetah-Base':5}); + expect(user.items.eggs).to.eql({'Cheetah':0}); + expect(user.items.hatchingPotions).to.eql({'Base':0}); + done(); + }); + }); + + it('hatches a premium pet', function(done) { + user.items.eggs = {'Wolf':1}; + user.items.hatchingPotions = {'Spooky':1}; + user.ops.hatch({params:{egg:'Wolf',hatchingPotion:'Spooky'}}, function(response) { + expect(response.message).to.eql(shared.i18n.t('messageHatched')); + expect(user.items.pets).to.eql({'Wolf-Spooky':5}); + expect(user.items.eggs).to.eql({'Wolf':0}); + expect(user.items.hatchingPotions).to.eql({'Spooky':0}); + done(); + }); + }); + + it('hatches a pet previously raised to a mount', function(done) { + user.items.eggs = {'Wolf':1}; + user.items.hatchingPotions = {'Base':1}; + user.items.pets = {'Wolf-Base':-1}; + user.ops.hatch({params:{egg:'Wolf',hatchingPotion:'Base'}}, function(response) { + expect(response.message).to.eql(shared.i18n.t('messageHatched')); + expect(user.items.pets).to.eql({'Wolf-Base':5}); + expect(user.items.eggs).to.eql({'Wolf':0}); + expect(user.items.hatchingPotions).to.eql({'Base':0}); + done(); + }); + }); + }); + }); +}); diff --git a/website/views/options/inventory/drops.jade b/website/views/options/inventory/drops.jade index de0b102248..4a98a9a57c 100644 --- a/website/views/options/inventory/drops.jade +++ b/website/views/options/inventory/drops.jade @@ -18,7 +18,7 @@ .badge.badge-info.stack-count {{points}} li.customize-menu - menu.hatchingPotion-menu(label=(env.t('hatchingPotions') + ' ({{potCount}})')) + menu.pets-menu(label=(env.t('hatchingPotions') + ' ({{potCount}})')) p.muted(ng-show='potCount < 1')=env.t('noHatchingPotions') div(ng-repeat='(pot,points) in ownedItems(user.items.hatchingPotions)') button.customize-option(class='Pet_HatchingPotion_{{::pot}}', @@ -146,7 +146,7 @@ li.customize-menu menu.pets-menu(label=env.t('magicHatchingPotions')) - div(ng-repeat='pot in Content.hatchingPotions', ng-if='pot.premium') + div(ng-repeat='pot in Content.hatchingPotions', ng-if='pot.premium && pot.canBuy') button.customize-option(class='Pet_HatchingPotion_{{::pot.key}}', popover='{{::pot.notes()}}', popover-append-to-body='true', popover-title!=env.t("potion", {potionType: "{{::pot.text()}}"}),