diff --git a/common/locales/en/subscriber.json b/common/locales/en/subscriber.json
index c448afe75f..64db64bb2d 100644
--- a/common/locales/en/subscriber.json
+++ b/common/locales/en/subscriber.json
@@ -61,7 +61,8 @@
"timeTravelersTitle": "Mysterious Time Travelers",
"timeTravelersPopoverNoSub": "You'll need a Mystic Hourglass to summon the mysterious Time Travelers! <%= linkStart %>Subscribers<%= linkEnd %> earn one Mystic Hourglass for every three months of consecutive subscribing. Come back when you have a Mystic Hourglass, and the Time Travelers will fetch you a Subscriber Item Set from the past.... or maybe even the future.",
"timeTravelersPopover": "We see you have a Mystic Hourglass, so we will happily travel back in time for you! Please choose the Mystery Item Set you would like. You can see a list of the past item sets <%= linkStart %>here<%= linkEnd %>! If those don't satisfy you, perhaps you'd be interested in one of our fashionably futuristic Steampunk Item Sets?",
- "mysticHourglassPopover": "Mystic Hourglass allow you to purchase previous months' subscriber sets.",
+ "timeTravelersAlreadyOwned": "Congratulations! You already own all of the Mystery Items. Thanks for supporting the site!",
+ "mysticHourglassPopover": "Mystic Hourglass allows you to purchase previous months' subscriber sets.",
"subUpdateCard": "Update Card",
"subUpdateTitle": "Update",
"subUpdateDescription": "Update the card to be charged."
diff --git a/test/server_side/controllers/user.test.js b/test/server_side/controllers/user.test.js
index ec3b447630..aac7bf69b7 100644
--- a/test/server_side/controllers/user.test.js
+++ b/test/server_side/controllers/user.test.js
@@ -552,4 +552,66 @@ describe('User Controller', function() {
});
});
});
+
+ describe('#addTenGems', function() {
+ var req, res, user;
+
+ beforeEach(function() {
+ user = {
+ _id: 'user-id',
+ balance: 5,
+ save: sinon.stub().yields()
+ };
+ req = { };
+ res = {
+ locals: { user: user },
+ send: sinon.spy()
+ };
+ });
+
+ it('adds 2.5 to user balance', function() {
+ userController.addTenGems(req, res);
+
+ expect(user.balance).to.eql(7.5);
+ expect(user.save).to.be.calledOnce;
+ });
+
+ it('sends back 204', function() {
+ userController.addTenGems(req, res);
+
+ expect(res.send).to.be.calledOnce;
+ expect(res.send).to.be.calledWith(204);
+ });
+ });
+
+ describe('#addHourglass', function() {
+ var req, res, user;
+
+ beforeEach(function() {
+ user = {
+ _id: 'user-id',
+ purchased: { plan: { consecutive: { trinkets: 3 } } },
+ save: sinon.stub().yields()
+ };
+ req = { };
+ res = {
+ locals: { user: user },
+ send: sinon.spy()
+ };
+ });
+
+ it('adds an hourglass to user', function() {
+ userController.addHourglass(req, res);
+
+ expect(user.purchased.plan.consecutive.trinkets).to.eql(4);
+ expect(user.save).to.be.calledOnce;
+ });
+
+ it('sends back 204', function() {
+ userController.addHourglass(req, res);
+
+ expect(res.send).to.be.calledOnce;
+ expect(res.send).to.be.calledWith(204);
+ });
+ });
});
diff --git a/test/spec/controllers/footerCtrlSpec.js b/test/spec/controllers/footerCtrlSpec.js
new file mode 100644
index 0000000000..7b12bc2875
--- /dev/null
+++ b/test/spec/controllers/footerCtrlSpec.js
@@ -0,0 +1,85 @@
+'use strict';
+
+describe('Footer Controller', function() {
+ var scope, user;
+
+ beforeEach(inject(function($rootScope, $controller) {
+ console.log(window.env.NODE_ENV);
+ user = specHelper.newUser();
+ var User = {log: sandbox.stub(), set: sandbox.stub(), user: user};
+ scope = $rootScope.$new();
+ $controller('FooterCtrl', {$scope: scope, User: User});
+ }));
+
+ context('Debug mode', function() {
+ before(function() {
+ window.env.NODE_ENV = 'test';
+ });
+
+ after(function() {
+ delete window.env.NODE_ENV;
+ });
+
+ describe('#setHealthLow', function(){
+ it('sets user health to 1');
+ });
+
+ describe('#addMissedDay', function(){
+ beforeEach(function() {
+ sandbox.stub(confirm).returns(true);
+ });
+
+ it('Cancels if confirm box is not confirmed');
+
+ it('allows multiple days');
+
+ it('sets users last cron');
+
+ it('notifies uers');
+ });
+
+ describe('#addTenGems', function() {
+ it('posts to /user/addTenGems', inject(function($httpBackend) {
+ $httpBackend.expectPOST('/api/v2/user/addTenGems').respond({});
+
+ scope.addTenGems();
+
+ $httpBackend.flush();
+ }));
+ });
+
+ describe('#addHourglass', function() {
+ it('posts to /user/addHourglass', inject(function($httpBackend) {
+ $httpBackend.expectPOST('/api/v2/user/addHourglass').respond({});
+
+ scope.addHourglass();
+
+ $httpBackend.flush();
+ }));
+ });
+
+ describe('#addGold', function() {
+ it('adds 500 gold to user');
+ });
+
+ describe('#addMana', function() {
+ it('adds 500 mana to user');
+ });
+
+ describe('#addLevelsAndGold', function() {
+ it('adds 10000 experience to user');
+
+ it('adds 10000 gp to user');
+
+ it('adds 10000 mp to user');
+ });
+
+ describe('#addOneLevel', function() {
+ it('adds one level to user');
+ });
+
+ describe('#addBossQuestProgressUp', function() {
+ it('adds 1000 progress to quest.progress.up');
+ });
+ });
+});
diff --git a/test/spec/controllers/inventoryCtrlSpec.js b/test/spec/controllers/inventoryCtrlSpec.js
index f9afeb0449..acdcc86840 100644
--- a/test/spec/controllers/inventoryCtrlSpec.js
+++ b/test/spec/controllers/inventoryCtrlSpec.js
@@ -12,6 +12,7 @@ describe('Inventory Controller', function() {
user = specHelper.newUser({
balance: 4,
items: {
+ gear: { owned: {} },
eggs: { Cactus: 1 },
hatchingPotions: { Base: 1 },
food: { Meat: 1 },
@@ -155,4 +156,16 @@ describe('Inventory Controller', function() {
expect(possibleValues).to.contain(cardsModalScope.cardMessage);
});
});
+
+ describe('#hasAllTimeTravelerItems', function() {
+ it('returns false if there are items left in the time traveler store', function() {
+ expect(scope.hasAllTimeTravelerItems()).to.eql(false);
+ });
+
+ it('returns true if there are no items left to purchase', inject(function(Content) {
+ sandbox.stub(Content, 'timeTravelerStore').returns({});
+
+ expect(scope.hasAllTimeTravelerItems()).to.eql(true);
+ }));
+ });
});
diff --git a/website/public/js/controllers/footerCtrl.js b/website/public/js/controllers/footerCtrl.js
index a12225f8e3..a25972fc81 100644
--- a/website/public/js/controllers/footerCtrl.js
+++ b/website/public/js/controllers/footerCtrl.js
@@ -69,48 +69,62 @@ function($scope, $rootScope, User, $http, Notification, ApiUrl) {
* Debug functions. Note that the server route for gems is only available if process.env.DEBUG=true
*/
if (_.contains(['development','test'],window.env.NODE_ENV)) {
+
$scope.setHealthLow = function(){
User.set({
'stats.hp': 1
});
- }
+ };
+
$scope.addMissedDay = function(numberOfDays){
if (!confirm("Are you sure you want to reset the day by " + numberOfDays + " day(s)?")) return;
var dayBefore = moment(User.user.lastCron).subtract(numberOfDays, 'days').toDate();
User.set({'lastCron': dayBefore});
Notification.text('-' + numberOfDays + ' day(s), remember to refresh');
- }
+ };
+
$scope.addTenGems = function(){
$http.post(ApiUrl.get() + '/api/v2/user/addTenGems').success(function(){
User.log({});
})
- }
+ };
+
+ $scope.addHourglass = function(){
+ $http.post(ApiUrl.get() + '/api/v2/user/addHourglass').success(function(){
+ User.log({});
+ })
+ };
+
$scope.addGold = function(){
User.set({
'stats.gp': User.user.stats.gp + 500,
});
- }
+ };
+
$scope.addMana = function(){
User.set({
'stats.mp': User.user.stats.mp + 500,
});
- }
+ };
+
$scope.addLevelsAndGold = function(){
User.set({
'stats.exp': User.user.stats.exp + 10000,
'stats.gp': User.user.stats.gp + 10000,
'stats.mp': User.user.stats.mp + 10000
});
- }
+ };
+
$scope.addOneLevel = function(){
User.set({
'stats.exp': User.user.stats.exp + (Math.round(((Math.pow(User.user.stats.lvl, 2) * 0.25) + (10 * User.user.stats.lvl) + 139.75) / 10) * 10)
});
- }
+ };
+
$scope.addBossQuestProgressUp = function(){
User.set({
'party.quest.progress.up': User.user.party.quest.progress.up + 1000
});
- }
+ };
}
}])
diff --git a/website/public/js/controllers/inventoryCtrl.js b/website/public/js/controllers/inventoryCtrl.js
index 4edad98680..e140a3798e 100644
--- a/website/public/js/controllers/inventoryCtrl.js
+++ b/website/public/js/controllers/inventoryCtrl.js
@@ -228,6 +228,13 @@ habitrpg.controller("InventoryCtrl",
});
};
+ $scope.hasAllTimeTravelerItems = function(items) {
+ var itemsLeftInTimeTravlerStore = Content.timeTravelerStore(user.items.gear.owned);
+ var keys = Object.keys(itemsLeftInTimeTravlerStore);
+
+ return keys.length === 0;
+ };
+
function _updateDropAnimalCount(items) {
$scope.petCount = Shared.count.beastMasterProgress(items.pets);
$scope.mountCount = Shared.count.mountMasterProgress(items.mounts);
diff --git a/website/src/controllers/user.js b/website/src/controllers/user.js
index f961ee5918..80a8321191 100644
--- a/website/src/controllers/user.js
+++ b/website/src/controllers/user.js
@@ -412,6 +412,25 @@ api.addTenGems = function(req, res, next) {
})
}
+/*
+ ------------------------------------------------------------------------
+ Hourglass
+ ------------------------------------------------------------------------
+ */
+
+// api.unlock // see Shared.ops
+
+api.addHourglass = function(req, res, next) {
+ var user = res.locals.user;
+
+ user.purchased.plan.consecutive.trinkets += 1;
+
+ user.save(function(err){
+ if (err) return next(err);
+ res.send(204);
+ })
+}
+
/*
------------------------------------------------------------------------
Tags
diff --git a/website/src/routes/apiv2.coffee b/website/src/routes/apiv2.coffee
index 396747fcf4..db26ac57a7 100644
--- a/website/src/routes/apiv2.coffee
+++ b/website/src/routes/apiv2.coffee
@@ -783,6 +783,10 @@ module.exports = (swagger, v2) ->
spec: method:'POST'
action: user.addTenGems
+ api["/user/addHourglass"] =
+ spec: method:'POST'
+ action: user.addHourglass
+
_.each api, (route, path) ->
## Spec format is:
# spec:
diff --git a/website/views/options/inventory/time-travelers.jade b/website/views/options/inventory/time-travelers.jade
index 7e7332429a..4b8277038f 100644
--- a/website/views/options/inventory/time-travelers.jade
+++ b/website/views/options/inventory/time-travelers.jade
@@ -1,23 +1,22 @@
.container-fluid
- .stable.row(ng-if='user.purchased.plan.consecutive.trinkets <= 0'): .col-xs-12
- .npc_timetravelers.pull-left-sm.col-centered
+ .stable.row: .col-xs-12
+ - var hasTrinkets = 'user.purchased.plan.consecutive.trinkets > 0'
+ .pull-left-sm.col-centered(ng-class='#{hasTrinkets} ? "npc_timetravelers_active" : "npc_timetravelers"')
.popover.static-popover.fade.right.in.pull-left-sm.col-centered
.arrow.hidden-xs
- h3.popover-title!=env.t('timeTravelersTitleNoSub', {linkStartTyler: "", linkStartVicky: "", linkEnd: ""})
- .popover-content
+ h3.popover-title(ng-if='#{hasTrinkets}')=env.t('timeTravelersTitle')
+ h3.popover-title(ng-if='!(#{hasTrinkets})')!=env.t('timeTravelersTitleNoSub', {linkStartTyler: "", linkStartVicky: "", linkEnd: ""})
+ .popover-content(ng-if='!(#{hasTrinkets})')
p!=env.t('timeTravelersPopoverNoSub', {linkStart: "", linkEnd: ""})
-
- .stable.row(ng-if='user.purchased.plan.consecutive.trinkets > 0'): .col-xs-12
- .npc_timetravelers_active.pull-left-sm.col-centered
- .popover.static-popover.fade.right.in.pull-left-sm.col-centered
- .arrow.hidden-xs
- h3.popover-title=env.t('timeTravelersTitle')
- .popover-content
+ .popover-content(ng-if='#{hasTrinkets}')
.pull-right
span.inventory_special_trinket.inline-gems
b x{{user.purchased.plan.consecutive.trinkets}}
p!=env.t('timeTravelersPopover', {linkStart: "", linkEnd: ""})
+ .row: .col-md-7
+ .alert.alert-info(ng-if='hasAllTimeTravelerItems()')=env.t('timeTravelersAlreadyOwned')
+
.row: .col-md-12
li.customize-menu.inventory-gear
menu.pets-menu(label='{{::set.text}}', ng-repeat='set in Content.timeTravelerStore(user.items.gear.owned)')
diff --git a/website/views/shared/footer.jade b/website/views/shared/footer.jade
index 2e81898d9c..06bfb26e7c 100644
--- a/website/views/shared/footer.jade
+++ b/website/views/shared/footer.jade
@@ -80,7 +80,8 @@ footer.footer(ng-controller='FooterCtrl')
a.btn.btn-default(ng-click='addMissedDay(1)') +1 Missed Day
a.btn.btn-default(ng-click='addMissedDay(2)') +2 Missed Days
a.btn.btn-default(ng-click='addTenGems()') +10 Gems
- a.btn.btn-default(ng-click='addGold()') +GP
+ a.btn.btn-default(ng-click='addHourglass()') +1 Mystic Hourglass
+ a.btn.btn-default(ng-click='addGold()') +500GP
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