diff --git a/common/script/content/index.js b/common/script/content/index.js index 72415dc14f..d59da2aaea 100644 --- a/common/script/content/index.js +++ b/common/script/content/index.js @@ -594,6 +594,14 @@ api.questMounts = _.transform(api.questEggs, function(m, egg) { })); }); +api.premiumMounts = _.transform(api.dropEggs, function(m, egg) { + return _.defaults(m, _.transform(api.hatchingPotions, function(m2, pot) { + if (pot.premium) { + return m2[egg.key + "-" + pot.key] = true; + } + })); +}); + api.food = { Meat: { text: t('foodMeat'), diff --git a/test/api/v3/integration/debug/POST-debug_modify-inventory.test.js b/test/api/v3/integration/debug/POST-debug_modify-inventory.test.js new file mode 100644 index 0000000000..93f9081492 --- /dev/null +++ b/test/api/v3/integration/debug/POST-debug_modify-inventory.test.js @@ -0,0 +1,160 @@ +/* eslint-disable camelcase */ + +import nconf from 'nconf'; +import { + generateUser, +} from '../../../../helpers/api-v3-integration.helper'; + +describe('POST /debug/modify-inventory', () => { + let user, originalItems; + + before(async () => { + originalItems = { + gear: { owned: { armor_base_0: true } }, + special: { + snowball: 1, + }, + pets: { + 'Wolf-Desert': 5, + }, + mounts: { + 'Wolf-Desert': true, + }, + eggs: { + Wolf: 5, + }, + hatchingPotions: { + Desert: 5, + }, + food: { + Watermelon: 5, + }, + quests: { + gryphon: 5, + }, + }; + user = await generateUser({ + items: originalItems, + }); + }); + + afterEach(() => { + nconf.set('IS_PROD', false); + }); + + it('sets equipment', async () => { + let gear = { + weapon_healer_2: true, + weapon_wizard_1: true, + weapon_special_critical: true, + }; + + await user.post('/debug/modify-inventory', { + gear, + }); + + await user.sync(); + + expect(user.items.gear.owned).to.eql(gear); + }); + + it('sets special spells', async () => { + let special = { + shinySeed: 3, + }; + + await user.post('/debug/modify-inventory', { + special, + }); + + await user.sync(); + + expect(user.items.special).to.eql(special); + }); + + it('sets mounts', async () => { + let mounts = { + 'Orca-Base': true, + 'Mammoth-Base': true, + }; + + await user.post('/debug/modify-inventory', { + mounts, + }); + + await user.sync(); + + expect(user.items.mounts).to.eql(mounts); + }); + + it('sets eggs', async () => { + let eggs = { + Gryphon: 3, + Hedgehog: 7, + }; + + await user.post('/debug/modify-inventory', { + eggs, + }); + + await user.sync(); + + expect(user.items.eggs).to.eql(eggs); + }); + + it('sets hatching potions', async () => { + let hatchingPotions = { + White: 7, + Spooky: 2, + }; + + await user.post('/debug/modify-inventory', { + hatchingPotions, + }); + + await user.sync(); + + expect(user.items.hatchingPotions).to.eql(hatchingPotions); + }); + + it('sets food', async () => { + let food = { + Meat: 5, + Candy_Red: 7, + }; + + await user.post('/debug/modify-inventory', { + food, + }); + + await user.sync(); + + expect(user.items.food).to.eql(food); + }); + + it('sets quests', async () => { + let quests = { + whale: 5, + cheetah: 10, + }; + + await user.post('/debug/modify-inventory', { + quests, + }); + + await user.sync(); + + expect(user.items.quests).to.eql(quests); + }); + + it('returns error when not in production mode', async () => { + nconf.set('IS_PROD', true); + + await expect(user.post('/debug/modify-inventory')) + .eventually.be.rejected.and.to.deep.equal({ + code: 404, + error: 'NotFound', + message: 'Not found.', + }); + }); +}); diff --git a/test/api/v3/integration/debug/POST-debug_quest-progress.test.js b/test/api/v3/integration/debug/POST-debug_quest-progress.test.js new file mode 100644 index 0000000000..3ae3d48882 --- /dev/null +++ b/test/api/v3/integration/debug/POST-debug_quest-progress.test.js @@ -0,0 +1,63 @@ +import nconf from 'nconf'; +import { + generateUser, +} from '../../../../helpers/api-v3-integration.helper'; + +describe('POST /debug/quest-progress', () => { + let user; + + beforeEach(async () => { + user = await generateUser(); + }); + + afterEach(() => { + nconf.set('IS_PROD', false); + }); + + it('errors if user is not on a quest', async () => { + await expect(user.post('/debug/quest-progress')) + .to.eventually.be.rejected.and.to.deep.equal({ + code: 400, + error: 'BadRequest', + message: 'User is not on a valid quest.', + }); + }); + + it('increases boss quest progress by 1000', async () => { + await user.update({ + 'party.quest.key': 'whale', + }); + + await user.post('/debug/quest-progress'); + + await user.sync(); + + expect(user.party.quest.progress.up).to.eql(1000); + }); + + it('increases collection quest progress by 300 items', async () => { + await user.update({ + 'party.quest.key': 'evilsanta2', + }); + + await user.post('/debug/quest-progress'); + + await user.sync(); + + expect(user.party.quest.progress.collect).to.eql({ + tracks: 300, + branches: 300, + }); + }); + + it('returns error when not in production mode', async () => { + nconf.set('IS_PROD', true); + + await expect(user.post('/debug/quest-progress')) + .eventually.be.rejected.and.to.deep.equal({ + code: 404, + error: 'NotFound', + message: 'Not found.', + }); + }); +}); diff --git a/website/client/js/controllers/footerCtrl.js b/website/client/js/controllers/footerCtrl.js index bca27a04d8..2d07aff430 100644 --- a/website/client/js/controllers/footerCtrl.js +++ b/website/client/js/controllers/footerCtrl.js @@ -118,15 +118,63 @@ function($scope, $rootScope, User, $http, Notification, ApiUrl, Social) { }); }; - $scope.addBossQuestProgressUp = function(){ - //@TODO: Route? - User.set({ - 'party.quest.progress.up': User.user.party.quest.progress.up + 1000 - }); + $scope.addQuestProgress = function(){ + $http({ + method: "POST", + url: 'api/v3/debug/quest-progress' + }) + .then(function (response) { + Notification.text('Quest progress increased'); + User.sync(); + }) }; $scope.makeAdmin = function () { User.makeAdmin(); }; + + $scope.openModifyInventoryModal = function () { + $rootScope.openModal('modify-inventory', {controller: 'FooterCtrl', scope: $scope }); + $scope.showInv = { }; + $scope.inv = { + gear: {}, + special: {}, + pets: {}, + mounts: {}, + eggs: {}, + hatchingPotions: {}, + food: {}, + quests: {}, + }; + $scope.setAllItems = function (type, value) { + var set = $scope.inv[type]; + + for (var item in set) { + if (set.hasOwnProperty(item)) { + set[item] = value; + } + } + }; + }; + + $scope.modifyInventory = function () { + $http({ + method: "POST", + url: 'api/v3/debug/modify-inventory', + data: { + gear: $scope.showInv.gear ? $scope.inv.gear : null, + special: $scope.showInv.special ? $scope.inv.special : null, + pets: $scope.showInv.pets ? $scope.inv.pets : null, + mounts: $scope.showInv.mounts ? $scope.inv.mounts : null, + eggs: $scope.showInv.eggs ? $scope.inv.eggs : null, + hatchingPotions: $scope.showInv.hatchingPotions ? $scope.inv.hatchingPotions : null, + food: $scope.showInv.food ? $scope.inv.food : null, + quests: $scope.showInv.quests ? $scope.inv.quests : null, + } + }) + .then(function (response) { + Notification.text('Inventory updated. Refresh or sync.'); + }) + }; } }]) diff --git a/website/server/controllers/api-v3/auth.js b/website/server/controllers/api-v3/auth.js index 7295cce9b7..f8eabf4c82 100644 --- a/website/server/controllers/api-v3/auth.js +++ b/website/server/controllers/api-v3/auth.js @@ -373,7 +373,7 @@ api.updatePassword = { }; /** - * @api {post} /api/v3/user/reset-password Reser password + * @api {post} /api/v3/user/reset-password Reset password * @apiDescription Reset the user password * @apiVersion 3.0.0 * @apiName ResetPassword @@ -427,7 +427,7 @@ api.resetPassword = { /** * @api {put} /api/v3/user/auth/update-email Update email - * @apiDescription Che the user email + * @apiDescription Change the user email address * @apiVersion 3.0.0 * @apiName UpdateEmail * @apiGroup User diff --git a/website/server/controllers/api-v3/debug.js b/website/server/controllers/api-v3/debug.js index 8824414be5..9f6d344546 100644 --- a/website/server/controllers/api-v3/debug.js +++ b/website/server/controllers/api-v3/debug.js @@ -1,5 +1,8 @@ import { authWithHeaders } from '../../middlewares/api-v3/auth'; import ensureDevelpmentMode from '../../middlewares/api-v3/ensureDevelpmentMode'; +import { BadRequest } from '../../libs/api-v3/errors'; +import { content } from '../../../../common'; +import _ from 'lodash'; let api = {}; @@ -101,4 +104,87 @@ api.setCron = { // }, // }; +/** + * @api {post} /api/v3/debug/modify-inventory Manipulate user's inventory + * @apiDescription Only available in development mode. + * @apiVersion 3.0.0 + * @apiName modifyInventory + * @apiGroup Development + * + * @apiSuccess {Object} data An empty Object + */ +api.modifyInventory = { + method: 'POST', + url: '/debug/modify-inventory', + middlewares: [ensureDevelpmentMode, authWithHeaders()], + async handler (req, res) { + let user = res.locals.user; + let { gear } = req.body; + + if (gear) { + user.items.gear.owned = gear; + } + + [ + 'special', + 'pets', + 'mounts', + 'eggs', + 'hatchingPotions', + 'food', + 'quests', + ].forEach((type) => { + if (req.body[type]) { + user.items[type] = req.body[type]; + } + }); + + await user.save(); + + res.respond(200, {}); + }, +}; + +/** + * @api {post} /api/v3/debug/quest-progress Artificially accelerate quest progress + * @apiDescription Only available in development mode. + * @apiVersion 3.0.0 + * @apiName questProgress + * @apiGroup Development + * + * @apiSuccess {Object} data An empty Object + */ +api.questProgress = { + method: 'POST', + url: '/debug/quest-progress', + middlewares: [ensureDevelpmentMode, authWithHeaders()], + async handler (req, res) { + let user = res.locals.user; + let key = _.get(user, 'party.quest.key'); + let quest = content.quests[key]; + + if (!quest) { + throw new BadRequest('User is not on a valid quest.'); + } + + if (quest.boss) { + user.party.quest.progress.up += 1000; + } + + if (quest.collect) { + let collect = user.party.quest.progress.collect; + _.each(quest.collect, (details, item) => { + collect[item] = collect[item] || 0; + collect[item] += 300; + }); + } + + user.markModified('party.quest.progress'); + + await user.save(); + + res.respond(200, {}); + }, +}; + module.exports = api; diff --git a/website/server/controllers/api-v3/modelsPaths.js b/website/server/controllers/api-v3/modelsPaths.js index b14d88b2b7..dc168b98b4 100644 --- a/website/server/controllers/api-v3/modelsPaths.js +++ b/website/server/controllers/api-v3/modelsPaths.js @@ -6,7 +6,7 @@ let tasksModels = ['habit', 'daily', 'todo', 'reward']; let allModels = ['user', 'tag', 'challenge', 'group'].concat(tasksModels); /** - * @api {get} /api/v3s/models/:model/paths Get all paths for the specified model. + * @api {get} /api/v3/models/:model/paths Get all paths for the specified model. * @apiDescription Doesn't require authentication * @apiVersion 3.0.0 * @apiName GetUserModelPaths diff --git a/website/server/controllers/api-v3/quests.js b/website/server/controllers/api-v3/quests.js index 832e90915a..9107fda8d6 100644 --- a/website/server/controllers/api-v3/quests.js +++ b/website/server/controllers/api-v3/quests.js @@ -249,7 +249,7 @@ api.rejectQuest = { /** - * @api {post} /api/v3/groups/:groupId/quests/force-start Accept a pending quest + * @api {post} /api/v3/groups/:groupId/quests/force-start Force-start a pending quest * @apiVersion 3.0.0 * @apiName ForceQuestStart * @apiGroup Group diff --git a/website/server/controllers/api-v3/tasks.js b/website/server/controllers/api-v3/tasks.js index a6a25fd7ff..3ed454c666 100644 --- a/website/server/controllers/api-v3/tasks.js +++ b/website/server/controllers/api-v3/tasks.js @@ -54,7 +54,7 @@ async function _createTasks (req, res, user, challenge) { } /** - * @api {post} /api/v3/tasks/user Create a new task the user. + * @api {post} /api/v3/tasks/user Create a new task belonging to the user. * @apiDescription Can be passed an object to create a single task or an array of objects to create multiple tasks. * @apiVersion 3.0.0 * @apiName CreateUserTasks diff --git a/website/server/controllers/api-v3/user.js b/website/server/controllers/api-v3/user.js index de06b90352..32cc1fb7bb 100644 --- a/website/server/controllers/api-v3/user.js +++ b/website/server/controllers/api-v3/user.js @@ -177,7 +177,7 @@ api.updateUser = { }; /** - * @api {delete} /api/v3/user DELETE an authenticated user's account + * @api {delete} /api/v3/user Delete an authenticated user's account * @apiVersion 3.0.0 * @apiName UserDelete * @apiGroup User @@ -240,7 +240,7 @@ function _cleanChecklist (task) { } /** - * @api {get} /api/v3/user/anonymized + * @api {get} /api/v3/user/anonymized Get anonymized user data * @apiVersion 3.0.0 * @apiName UserGetAnonymized * @apiGroup User @@ -886,12 +886,12 @@ api.userOpenMysteryItem = { }; /* -* @api {post} /api/v3/user/webhook +* @api {post} /api/v3/user/webhook Create a new webhook * @apiVersion 3.0.0 * @apiName UserAddWebhook * @apiGroup User * -* @apiParam {string} url Body parameter - The webhook's urò +* @apiParam {string} url Body parameter - The webhook's URL * @apiParam {boolean} enabled Body parameter - If the webhook should be enabled * * @apiSuccess {Object} data The created webhook @@ -909,13 +909,13 @@ api.addWebhook = { }; /* -* @api {put} /api/v3/user/webhook/:id +* @api {put} /api/v3/user/webhook/:id Edit a webhook * @apiVersion 3.0.0 * @apiName UserUpdateWebhook * @apiGroup User * * @apiParam {UUID} id The id of the webhook to update -* @apiParam {string} url Body parameter - The webhook's urò +* @apiParam {string} url Body parameter - The webhook's URL * @apiParam {boolean} enabled Body parameter - If the webhook should be enabled * * @apiSuccess {Object} data The updated webhook @@ -933,7 +933,7 @@ api.updateWebhook = { }; /* -* @api {delete} /api/v3/user/webhook/:id +* @api {delete} /api/v3/user/webhook/:id Delete a webhook * @apiVersion 3.0.0 * @apiName UserDeleteWebhook * @apiGroup User diff --git a/website/views/shared/footer.jade b/website/views/shared/footer.jade index cc94250844..6246f09cc8 100644 --- a/website/views/shared/footer.jade +++ b/website/views/shared/footer.jade @@ -91,9 +91,10 @@ footer.footer(ng-controller='FooterCtrl') a.btn.btn-default(ng-click='addMana()') +MP a.btn.btn-default(ng-click='addLevelsAndGold()') +Exp +GP +MP a.btn.btn-default(ng-click='addOneLevel()') +1 Level - a.btn.btn-default(ng-click='addBossQuestProgressUp()') +1000 Boss Quest Progress Up + a.btn.btn-default(ng-click='addQuestProgress()' tooltip="+1000 to boss quests. 300 items to collection quests") Quest Progress Up // TODO Re-enable after v3 prod testing // a.btn.btn-default(ng-click='makeAdmin()') Make Admin + a.btn.btn-default(ng-click='openModifyInventoryModal()') Modify Inventory div(ng-init='deferredScripts()') diff --git a/website/views/shared/modals/index.jade b/website/views/shared/modals/index.jade index a57ee62189..c492e09ee1 100644 --- a/website/views/shared/modals/index.jade +++ b/website/views/shared/modals/index.jade @@ -19,6 +19,7 @@ include ./level-up.jade include ./hatch-pet.jade include ./raise-pet.jade include ./won-challenge.jade +include ./modify-inventory.jade //- Settings script(type='text/ng-template', id='modals/change-day-start.html') diff --git a/website/views/shared/modals/modify-inventory.jade b/website/views/shared/modals/modify-inventory.jade new file mode 100644 index 0000000000..a7a87a2de2 --- /dev/null +++ b/website/views/shared/modals/modify-inventory.jade @@ -0,0 +1,244 @@ +script(type='text/ng-template', id='modals/modify-inventory.html') + .modal-header + h4 Modify Inventory for {{::user.profile.name}} + .modal-body + .container-fluid + .row + .col-xs-12 + button.btn.btn-default.pull-right(ng-if="!showInv.gear", ng-click="showInv.gear = true") Show Gear + h4 Gear + div(ng-if="showInv.gear") + button.btn.btn-default(ng-click="setAllItems('gear', true)") Own All + button.btn.btn-default(ng-click="setAllItems('gear', false)") Previously Own All + button.btn.btn-default(ng-click="setAllItems('gear', undefined)") Never Own All + + hr + + ul.list-group + li.list-group-item(ng-repeat="item in Content.gear.flat" ng-init="inv.gear[item.key] = user.items.gear.owned[item.key]") + .pull-left(class="shop_{{::item.key}}" style="margin-right: 10px") + | {{::item.text()}} + + .clearfix + label.radio-inline + input(type="radio" name="gear-{{::item.key}}" ng-model="inv.gear[item.key]" ng-value="true") + | Owned + label.radio-inline + input(type="radio" name="gear-{{::item.key}}" ng-model="inv.gear[item.key]" ng-value="false") + | Previously Owned + label.radio-inline + input(type="radio" name="gear-{{::item.key}}" ng-model="inv.gear[item.key]" ng-value="undefined") + | Never Owned + + hr + + .row + .col-xs-12 + button.btn.btn-default.pull-right(ng-if="!showInv.special", ng-click="showInv.special = true") Show Special Items + h4 Special Items + div(ng-if="showInv.special") + button.btn.btn-default(ng-click="setAllItems('special', 999)") Set All to 999 + button.btn.btn-default(ng-click="setAllItems('special', 0)") Set All to 0 + button.btn.btn-default(ng-click="setAllItems('special', undefined)") Set All to undefined + + hr + + ul.list-group + li.list-group-item(ng-repeat="item in Content.special" ng-init="inv.special[item.key] = user.items.special[item.key]") + .form-inline.clearfix + .pull-left(class="inventory_special_{{::item.key}}" style="margin-right: 10px") + p {{::item.text()}} + input.form-control(type="number" ng-model="inv.special[item.key]") + + hr + + .row + .col-xs-12 + button.btn.btn-default.pull-right(ng-if="!showInv.pets", ng-click="showInv.pets = true") Show Pets + h4 Pets + div(ng-if="showInv.pets") + button.btn.btn-default(ng-click="setAllItems('pets', 99)") Set All to 99 + button.btn.btn-default(ng-click="setAllItems('pets', 0)") Set All to 0 + button.btn.btn-default(ng-click="setAllItems('pets', -1)") Set All to -1 + button.btn.btn-default(ng-click="setAllItems('pets', undefined)") Set All to undefined + + hr + + h5 Drop Pets + ul.list-group + li.list-group-item(ng-repeat="(pet, value) in Content.pets" ng-init="inv.pets[pet] = user.items.pets[pet]") + .form-inline.clearfix + .pull-left(class="Pet-{{::pet}}" style="margin-right: 10px") + p {{::pet}} + input.form-control(type="number" ng-model="inv.pets[pet]") + + h5 Quest Pets + ul.list-group + li.list-group-item(ng-repeat="(pet, value) in Content.questPets" ng-init="inv.pets[pet] = user.items.pets[pet]") + .form-inline.clearfix + .pull-left(class="Pet-{{::pet}}" style="margin-right: 10px") + p {{::pet}} + input.form-control(type="number" ng-model="inv.pets[pet]") + + h5 Special Pets + ul.list-group + li.list-group-item(ng-repeat="(pet, value) in Content.specialPets" ng-init="inv.pets[pet] = user.items.pets[pet]") + .form-inline.clearfix + .pull-left(class="Pet-{{::pet}}" style="margin-right: 10px") + p {{::pet}} + input.form-control(type="number" ng-model="inv.pets[pet]") + + h5 Premium Pets + ul.list-group + li.list-group-item(ng-repeat="(pet, value) in Content.premiumPets" ng-init="inv.pets[pet] = user.items.pets[pet]") + .form-inline.clearfix + .pull-left(class="Pet-{{::pet}}" style="margin-right: 10px") + p {{::pet}} + input.form-control(type="number" ng-model="inv.pets[pet]") + + hr + + .row + .col-xs-12 + button.btn.btn-default.pull-right(ng-if="!showInv.mounts", ng-click="showInv.mounts = true") Show Mounts + h4 Mounts + div(ng-if="showInv.mounts") + button.btn.btn-default(ng-click="setAllItems('mounts', true)") Set all to Owned + button.btn.btn-default(ng-click="setAllItems('mounts', undefined)") Set all to Not Owned + + hr + + h5 Drop Mounts + ul.list-group + li.list-group-item(ng-repeat="(mount, value) in Content.mounts" ng-init="inv.mounts[mount] = user.items.mounts[mount]") + .pull-left(class="Mount_Icon_{{::mount}}" style="margin-right: 10px") + | {{::mount}} + .clearfix + label.radio-inline + input(type="radio" name="mounts-{{::mount}}" ng-model="inv.mounts[mount]" ng-value="true") + | Owned + label.radio-inline + input(type="radio" name="mounts-{{::mount}}" ng-model="inv.mounts[mount]" ng-value="undefined") + | Not Owned + + h5 Quest Mounts + ul.list-group + li.list-group-item(ng-repeat="(mount, value) in Content.questMounts" ng-init="inv.mounts[mount] = user.items.mounts[mount]") + .pull-left(class="Mount_Icon_{{::mount}}" style="margin-right: 10px") + | {{::mount}} + .clearfix + label.radio-inline + input(type="radio" name="mounts-{{::mount}}" ng-model="inv.mounts[mount]" ng-value="true") + | Owned + label.radio-inline + input(type="radio" name="mounts-{{::mount}}" ng-model="inv.mounts[mount]" ng-value="undefined") + | Not Owned + + h5 Special Mounts + ul.list-group + li.list-group-item(ng-repeat="(mount, value) in Content.specialMounts" ng-init="inv.mounts[mount] = user.items.mounts[mount]") + .pull-left(class="Mount_Icon_{{::mount}}" style="margin-right: 10px") + | {{::mount}} + .clearfix + label.radio-inline + input(type="radio" name="mounts-{{::mount}}" ng-model="inv.mounts[mount]" ng-value="true") + | Owned + label.radio-inline + input(type="radio" name="mounts-{{::mount}}" ng-model="inv.mounts[mount]" ng-value="undefined") + | Not Owned + + h5 Premium Mounts + ul.list-group + li.list-group-item(ng-repeat="(mount, value) in Content.premiumMounts" ng-init="inv.mounts[mount] = user.items.mounts[mount]") + .pull-left(class="Mount_Icon_{{::mount}}" style="margin-right: 10px") + | {{::mount}} + .clearfix + label.radio-inline + input(type="radio" name="mounts-{{::mount}}" ng-model="inv.mounts[mount]" ng-value="true") + | Owned + label.radio-inline + input(type="radio" name="mounts-{{::mount}}" ng-model="inv.mounts[mount]" ng-value="undefined") + | Not Owned + + hr + + .row + .col-xs-12 + button.btn.btn-default.pull-right(ng-if="!showInv.hatchingPotions", ng-click="showInv.hatchingPotions = true") Show Hatching Potions + h4 Hatching Potions + div(ng-if="showInv.hatchingPotions") + button.btn.btn-default(ng-click="setAllItems('hatchingPotions', 999)") Set All to 999 + button.btn.btn-default(ng-click="setAllItems('hatchingPotions', 0)") Set All to 0 + button.btn.btn-default(ng-click="setAllItems('hatchingPotions', undefined)") Set All to undefined + + hr + + ul.list-group + li.list-group-item(ng-repeat="item in Content.hatchingPotions" ng-init="inv.hatchingPotions[item.key] = user.items.hatchingPotions[item.key]") + .form-inline.clearfix + .pull-left(class="Pet_HatchingPotion_{{::item.key}}" style="margin-right: 10px") + p {{::item.text()}} + input.form-control(type="number" ng-model="inv.hatchingPotions[item.key]") + + hr + + .row + .col-xs-12 + button.btn.btn-default.pull-right(ng-if="!showInv.eggs", ng-click="showInv.eggs = true") Show Eggs + h4 Eggs + div(ng-if="showInv.eggs") + button.btn.btn-default(ng-click="setAllItems('eggs', 999)") Set All to 999 + button.btn.btn-default(ng-click="setAllItems('eggs', 0)") Set All to 0 + button.btn.btn-default(ng-click="setAllItems('eggs', undefined)") Set All to undefined + + hr + + ul.list-group + li.list-group-item(ng-repeat="item in Content.eggs" ng-init="inv.eggs[item.key] = user.items.eggs[item.key]") + .form-inline.clearfix + .pull-left(class="Pet_Egg_{{::item.key}}" style="margin-right: 10px") + p {{::item.text()}} + input.form-control(type="number" ng-model="inv.eggs[item.key]") + + hr + + .row + .col-xs-12 + button.btn.btn-default.pull-right(ng-if="!showInv.food", ng-click="showInv.food = true") Show Food + h4 Food + div(ng-if="showInv.food") + button.btn.btn-default(ng-click="setAllItems('food', 999)") Set All to 999 + button.btn.btn-default(ng-click="setAllItems('food', 0)") Set All to 0 + button.btn.btn-default(ng-click="setAllItems('food', undefined)") Set All to undefined + + hr + + ul.list-group + li.list-group-item(ng-repeat="item in Content.food" ng-init="inv.food[item.key] = user.items.food[item.key]") + .form-inline.clearfix + .pull-left(class="Pet_Food_{{::item.key}}" style="margin-right: 10px") + p {{::item.text()}} + input.form-control(type="number" ng-model="inv.food[item.key]") + + hr + + .row + .col-xs-12 + button.btn.btn-default.pull-right(ng-if="!showInv.quests", ng-click="showInv.quests = true") Show Quests + h4 Quests + div(ng-if="showInv.quests") + button.btn.btn-default(ng-click="setAllItems('quests', 999)") Set All to 999 + button.btn.btn-default(ng-click="setAllItems('quests', 0)") Set All to 0 + button.btn.btn-default(ng-click="setAllItems('quests', undefined)") Set All to undefined + + hr + + ul.list-group + li.list-group-item(ng-repeat="item in Content.quests" ng-init="inv.quests[item.key] = user.items.quests[item.key]" ng-if="item.category !== 'world'") + .form-inline.clearfix + .pull-left(class="inventory_quest_scroll_{{::item.key}}" style="margin-right: 10px") + p {{::item.text()}} + input.form-control(type="number" ng-model="inv.quests[item.key]") + .modal-footer + button.btn.btn-default(ng-click="$close()")=env.t('close') + button.btn.btn-primary(ng-click="$close();modifyInventory()") Apply Changes