mirror of
https://github.com/sudoxnym/habitica.git
synced 2026-07-22 03:34:14 +00:00
Merge pull request #5938 from HabitRPG/sabrecat/timetravel-stable
Time Travel Stable
This commit is contained in:
commit
09ccb9584f
10 changed files with 416 additions and 43 deletions
|
|
@ -59,11 +59,21 @@
|
|||
"timeTravelers": "Time Travelers",
|
||||
"timeTravelersTitleNoSub": "<%= linkStartTyler %>Tyler<%= linkEnd %> and <%= linkStartVicky %>Vicky<%= linkEnd %>",
|
||||
"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?",
|
||||
"timeTravelersAlreadyOwned": "Congratulations! You already own all of the Mystery Items. Thanks for supporting the site!",
|
||||
"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 rare pet, mount, or 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 pet, mount, or 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?",
|
||||
"timeTravelersAlreadyOwned": "Congratulations! You already own everything the Time Travelers currently offer. 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."
|
||||
"subUpdateDescription": "Update the card to be charged.",
|
||||
"notEnoughHourglasses": "You don't have enough Mystic Hourglasses.",
|
||||
"hourglassBuyEquipSetConfirm": "Buy this full set of items for 1 Mystic Hourglass?",
|
||||
"hourglassBuyItemConfirm": "Buy this item for 1 Mystic Hourglass?",
|
||||
"petsAlreadyOwned": "Pet already owned.",
|
||||
"mountsAlreadyOwned": "Mount already owned.",
|
||||
"typeNotAllowedHourglass": "Item type not supported for purchase with Mystic Hourglass. Allowed types: ",
|
||||
"petsNotAllowedHourglass": "Pet not available for purchase with Mystic Hourglass.",
|
||||
"mountsNotAllowedHourglass": "Mount not available for purchase with Mystic Hourglass.",
|
||||
"hourglassPurchase": "Purchased an item using a Mystic Hourglass!",
|
||||
"hourglassPurchaseSet": "Purchased an item set using a Mystic Hourglass!"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1126,6 +1126,14 @@ api.specialMounts =
|
|||
'Orca-Base': 'orca'
|
||||
'Gryphon-RoyalPurple': 'royalPurpleGryphon'
|
||||
|
||||
api.timeTravelStable =
|
||||
pets:
|
||||
'Mammoth-Base': t('mammoth')
|
||||
'MantisShrimp-Base': t('mantisShrimp')
|
||||
mounts:
|
||||
'Mammoth-Base': t('mammoth')
|
||||
'MantisShrimp-Base': t('mantisShrimp')
|
||||
|
||||
api.hatchingPotions =
|
||||
Base: value: 2, text: t('hatchingPotionBase')
|
||||
White: value: 2, text: t('hatchingPotionWhite')
|
||||
|
|
@ -2042,7 +2050,7 @@ api.quests =
|
|||
]
|
||||
gp: 0
|
||||
exp: 650
|
||||
|
||||
|
||||
cheetah:
|
||||
text: t('questCheetahText')
|
||||
notes: t('questCheetahNotes')
|
||||
|
|
|
|||
|
|
@ -999,10 +999,10 @@ api.wrap = (user, main=true) ->
|
|||
cb? {code:200, message}, user.items.quests
|
||||
|
||||
buyMysterySet: (req, cb, analytics)->
|
||||
return cb?({code:401, message:"You don't have enough Mystic Hourglasses"}) unless user.purchased.plan.consecutive.trinkets>0
|
||||
return cb?({code:401, message:i18n.t('notEnoughHourglasses', req.language)}) unless user.purchased.plan.consecutive.trinkets > 0
|
||||
mysterySet = content.timeTravelerStore(user.items.gear.owned)?[req.params.key]
|
||||
if window?.confirm?
|
||||
return unless window.confirm("Buy this full set of items for 1 Mystic Hourglass?")
|
||||
return unless window.confirm(i18n.t('hourglassBuyEquipSetConfirm'))
|
||||
return cb?({code:404, message:"Mystery set not found, or set already owned"}) unless mysterySet
|
||||
_.each mysterySet.items, (i)->
|
||||
user.items.gear.owned[i.key]=true
|
||||
|
|
@ -1016,7 +1016,28 @@ api.wrap = (user, main=true) ->
|
|||
analytics?.track('acquire item', analyticsData)
|
||||
|
||||
user.purchased.plan.consecutive.trinkets--
|
||||
cb? null, _.pick(user,$w 'items purchased.plan.consecutive')
|
||||
cb? {code:200, message:i18n.t('hourglassPurchaseSet', req.language)}, _.pick(user,$w 'items purchased.plan.consecutive')
|
||||
|
||||
hourglassPurchase: (req, cb, analytics)->
|
||||
{type, key} = req.params
|
||||
return cb?({code:403, message:i18n.t('typeNotAllowedHourglass', req.language) + JSON.stringify(_.keys(content.timeTravelStable))}) unless content.timeTravelStable[type]
|
||||
return cb?({code:403, message:i18n.t(type+'NotAllowedHourglass', req.language)}) unless _.contains(_.keys(content.timeTravelStable[type]), key)
|
||||
return cb?({code:403, message:i18n.t(type+'AlreadyOwned', req.language)}) if user.items[type][key]
|
||||
return cb?({code:403, message:i18n.t('notEnoughHourglasses', req.language)}) unless user.purchased.plan.consecutive.trinkets > 0
|
||||
user.purchased.plan.consecutive.trinkets--
|
||||
if type is 'pets'
|
||||
user.items.pets[key] = 5
|
||||
if type is 'mounts'
|
||||
user.items.mounts[key] = true
|
||||
analyticsData = {
|
||||
uuid: user._id,
|
||||
itemKey: key,
|
||||
itemType: type,
|
||||
acquireMethod: 'Hourglass',
|
||||
category: 'behavior'
|
||||
}
|
||||
analytics?.track('acquire item', analyticsData)
|
||||
cb? {code:200, message:i18n.t('hourglassPurchase', req.language)}, _.pick(user,$w 'items purchased.plan.consecutive')
|
||||
|
||||
sell: (req, cb) ->
|
||||
{key, type} = req.params
|
||||
|
|
|
|||
84
test/common/user.ops.buyMysterySet.test.js
Normal file
84
test/common/user.ops.buyMysterySet.test.js
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
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.buyMysterySet', function() {
|
||||
var user;
|
||||
|
||||
beforeEach(function() {
|
||||
user = {
|
||||
items: {
|
||||
gear: {
|
||||
owned: {
|
||||
weapon_warrior_0: true
|
||||
}
|
||||
}
|
||||
},
|
||||
purchased: {
|
||||
plan: {
|
||||
consecutive: {
|
||||
trinkets: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
shared.wrap(user);
|
||||
});
|
||||
|
||||
context('Mystery Sets', function() {
|
||||
|
||||
context('failure conditions', function() {
|
||||
|
||||
it('does not grant mystery sets without Mystic Hourglasses', function(done) {
|
||||
user.ops.buyMysterySet({params:{key:'201501'}}, function(response) {
|
||||
expect(response.message).to.eql("You don't have enough Mystic Hourglasses.");
|
||||
expect(user.items.gear.owned).to.eql({'weapon_warrior_0': true});
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('does not grant mystery set that has already been purchased', function(done) {
|
||||
user.purchased.plan.consecutive.trinkets = 1;
|
||||
user.items.gear.owned = {
|
||||
weapon_warrior_0: true,
|
||||
weapon_mystery_301404: true,
|
||||
armor_mystery_301404: true,
|
||||
head_mystery_301404: true,
|
||||
eyewear_mystery_301404: true
|
||||
};
|
||||
|
||||
user.ops.buyMysterySet({params:{key:'301404'}}, function(response) {
|
||||
expect(response.message).to.eql("Mystery set not found, or set already owned");
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('successful purchases', function() {
|
||||
|
||||
it('buys Steampunk Accessories Set', function(done) {
|
||||
user.purchased.plan.consecutive.trinkets = 1;
|
||||
|
||||
user.ops.buyMysterySet({params:{key:'301404'}}, function() {
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(0);
|
||||
expect(user.items.gear.owned).to.eql({
|
||||
weapon_warrior_0: true,
|
||||
weapon_mystery_301404: true,
|
||||
armor_mystery_301404: true,
|
||||
head_mystery_301404: true,
|
||||
eyewear_mystery_301404: true
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
132
test/common/user.ops.hourglassPurchase.test.js
Normal file
132
test/common/user.ops.hourglassPurchase.test.js
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
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.hourglassPurchase', function() {
|
||||
var user;
|
||||
|
||||
beforeEach(function() {
|
||||
user = {
|
||||
items: {
|
||||
pets: {},
|
||||
mounts: {},
|
||||
hatchingPotions: {}
|
||||
},
|
||||
purchased: {
|
||||
plan: {
|
||||
consecutive: {
|
||||
trinkets: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
shared.wrap(user);
|
||||
});
|
||||
|
||||
context('Time Travel Stable', function() {
|
||||
|
||||
context('failure conditions', function() {
|
||||
|
||||
it('does not allow purchase of unsupported item types', function(done) {
|
||||
user.ops.hourglassPurchase({params:{type: 'hatchingPotions', key: 'Base'}}, function(response) {
|
||||
expect(response.message).to.eql('Item type not supported for purchase with Mystic Hourglass. Allowed types: ["pets","mounts"]');
|
||||
expect(user.items.hatchingPotions).to.eql({});
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('does not grant pets without Mystic Hourglasses', function(done) {
|
||||
user.ops.hourglassPurchase({params:{type: 'pets', key: 'MantisShrimp-Base'}}, function(response) {
|
||||
expect(response.message).to.eql("You don't have enough Mystic Hourglasses.");
|
||||
expect(user.items.pets).to.eql({});
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('does not grant mounts without Mystic Hourglasses', function(done) {
|
||||
user.ops.hourglassPurchase({params:{type: 'mounts', key: 'MantisShrimp-Base'}}, function(response) {
|
||||
expect(response.message).to.eql("You don't have enough Mystic Hourglasses.");
|
||||
expect(user.items.mounts).to.eql({});
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('does not grant pet that has already been purchased', function(done) {
|
||||
user.purchased.plan.consecutive.trinkets = 1;
|
||||
user.items.pets = {
|
||||
'MantisShrimp-Base': true
|
||||
};
|
||||
|
||||
user.ops.hourglassPurchase({params:{type: 'pets', key: 'MantisShrimp-Base'}}, function(response) {
|
||||
expect(response.message).to.eql("Pet already owned.");
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('does not grant mount that has already been purchased', function(done) {
|
||||
user.purchased.plan.consecutive.trinkets = 1;
|
||||
user.items.mounts = {
|
||||
'MantisShrimp-Base': true
|
||||
};
|
||||
|
||||
user.ops.hourglassPurchase({params:{type: 'mounts', key: 'MantisShrimp-Base'}}, function(response) {
|
||||
expect(response.message).to.eql("Mount already owned.");
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('does not grant pet that is not part of the Time Travel Stable', function(done) {
|
||||
user.purchased.plan.consecutive.trinkets = 1;
|
||||
|
||||
user.ops.hourglassPurchase({params: {type: 'pets', key: 'Wolf-Veteran'}}, function(response) {
|
||||
expect(response.message).to.eql('Pet not available for purchase with Mystic Hourglass.');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('does not grant mount that is not part of the Time Travel Stable', function(done) {
|
||||
user.purchased.plan.consecutive.trinkets = 1;
|
||||
|
||||
user.ops.hourglassPurchase({params: {type: 'mounts', key: 'Orca-Base'}}, function(response) {
|
||||
expect(response.message).to.eql('Mount not available for purchase with Mystic Hourglass.');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('successful purchases', function() {
|
||||
|
||||
it('buys a pet', function(done) {
|
||||
user.purchased.plan.consecutive.trinkets = 2;
|
||||
|
||||
user.ops.hourglassPurchase({params: {type: 'pets', key: 'MantisShrimp-Base'}}, function(response) {
|
||||
expect(response.message).to.eql('Purchased an item using a Mystic Hourglass!');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(1);
|
||||
expect(user.items.pets).to.eql({'MantisShrimp-Base':5});
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('buys a mount', function(done) {
|
||||
user.purchased.plan.consecutive.trinkets = 2;
|
||||
|
||||
user.ops.hourglassPurchase({params: {type: 'mounts', key: 'MantisShrimp-Base'}}, function(response) {
|
||||
expect(response.message).to.eql('Purchased an item using a Mystic Hourglass!');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(1);
|
||||
expect(user.items.mounts).to.eql({'MantisShrimp-Base':true});
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -224,14 +224,64 @@ describe('Inventory Controller', function() {
|
|||
});
|
||||
|
||||
describe('#hasAllTimeTravelerItems', function() {
|
||||
it('returns false if there are items left in the time traveler store', function() {
|
||||
it('returns false if items remain for purchase with Mystic Hourglasses', 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({});
|
||||
|
||||
for (var item in Content.gear.flat) {
|
||||
if (item.indexOf('mystery') > -1) {
|
||||
user.items.gear.owned[item] = true;
|
||||
}
|
||||
}
|
||||
for (var pet in Content.timeTravelStable.pets) {
|
||||
user.items.pets[pet] = 5;
|
||||
}
|
||||
for (var mount in Content.timeTravelStable.mounts) {
|
||||
user.items.mounts[mount] = true;
|
||||
}
|
||||
|
||||
expect(scope.hasAllTimeTravelerItems()).to.eql(true);
|
||||
}));
|
||||
});
|
||||
|
||||
describe('#hasAllTimeTravelerItemsOfType', function() {
|
||||
it('returns false for Mystery Sets if there are sets left in the time traveler store', function() {
|
||||
expect(scope.hasAllTimeTravelerItemsOfType('mystery')).to.eql(false);
|
||||
});
|
||||
|
||||
it('returns true for Mystery Sets if there are no sets left to purchase', inject(function(Content) {
|
||||
for (var item in Content.gear.flat) {
|
||||
if (item.indexOf('mystery') > -1) {
|
||||
user.items.gear.owned[item] = true;
|
||||
}
|
||||
}
|
||||
|
||||
expect(scope.hasAllTimeTravelerItemsOfType('mystery')).to.eql(true);
|
||||
}));
|
||||
|
||||
it('returns false for pets if user does not own all pets in the Time Travel Stable', function() {
|
||||
expect(scope.hasAllTimeTravelerItemsOfType('pets')).to.eql(false);
|
||||
});
|
||||
|
||||
it('returns true for pets if user owns all pets in the Time Travel Stable', inject(function(Content) {
|
||||
for (var pet in Content.timeTravelStable.pets) {
|
||||
user.items.pets[pet] = 5;
|
||||
}
|
||||
|
||||
expect(scope.hasAllTimeTravelerItemsOfType('pets')).to.eql(true);
|
||||
}));
|
||||
|
||||
it('returns false for mounts if user does not own all mounts in the Time Travel Stable', function() {
|
||||
expect(scope.hasAllTimeTravelerItemsOfType('mounts')).to.eql(false);
|
||||
});
|
||||
|
||||
it('returns true for mounts if user owns all mounts in the Time Travel Stable', inject(function(Content) {
|
||||
for (var mount in Content.timeTravelStable.mounts) {
|
||||
user.items.mounts[mount] = true;
|
||||
}
|
||||
|
||||
expect(scope.hasAllTimeTravelerItemsOfType('mounts')).to.eql(true);
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -250,11 +250,32 @@ habitrpg.controller("InventoryCtrl",
|
|||
});
|
||||
};
|
||||
|
||||
$scope.hasAllTimeTravelerItems = function(items) {
|
||||
var itemsLeftInTimeTravlerStore = Content.timeTravelerStore(user.items.gear.owned);
|
||||
var keys = Object.keys(itemsLeftInTimeTravlerStore);
|
||||
$scope.hasAllTimeTravelerItems = function() {
|
||||
return ($scope.hasAllTimeTravelerItemsOfType('mystery') &&
|
||||
$scope.hasAllTimeTravelerItemsOfType('pets') &&
|
||||
$scope.hasAllTimeTravelerItemsOfType('mounts'));
|
||||
};
|
||||
|
||||
return keys.length === 0;
|
||||
$scope.hasAllTimeTravelerItemsOfType = function(type) {
|
||||
if (type === 'mystery') {
|
||||
var itemsLeftInTimeTravelerStore = Content.timeTravelerStore(user.items.gear.owned);
|
||||
var keys = Object.keys(itemsLeftInTimeTravelerStore);
|
||||
|
||||
return keys.length === 0;
|
||||
}
|
||||
if (type === 'pets' || type === 'mounts') {
|
||||
for (var key in Content.timeTravelStable[type]) {
|
||||
if (!user.items[type][key]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else return Console.log('Time Traveler item type must be in ["pets","mounts","mystery"]');
|
||||
};
|
||||
|
||||
$scope.clickTimeTravelItem = function(type,key) {
|
||||
if (user.purchased.plan.consecutive.trinkets < 1) return user.ops.hourglassPurchase({params:{type:type,key:key}});
|
||||
if (!window.confirm(window.env.t('hourglassBuyItemConfirm'))) return;
|
||||
user.ops.hourglassPurchase({params:{type:type,key:key}});
|
||||
};
|
||||
|
||||
function _updateDropAnimalCount(items) {
|
||||
|
|
|
|||
|
|
@ -180,13 +180,31 @@ module.exports = (swagger, v2) ->
|
|||
"/user/inventory/purchase/{type}/{key}":
|
||||
spec:
|
||||
method: 'POST'
|
||||
description: "Purchase a gem-purchaseable item from Alexander"
|
||||
description: "Purchase a Gem-purchasable item from Alexander"
|
||||
parameters:[
|
||||
path('type',"The type of object you're purchasing.",'string',['eggs','hatchingPotions','food','quests','special'])
|
||||
path('key',"The object key you're purchasing (call /content route for available keys)",'string')
|
||||
]
|
||||
action: user.purchase
|
||||
|
||||
"/user/inventory/hourglass/{type}/{key}":
|
||||
spec:
|
||||
method: 'POST'
|
||||
description: "Purchase a pet or mount using a Mystic Hourglass"
|
||||
parameters:[
|
||||
path('type',"The type of object you're purchasing.",'string',['pets','mounts'])
|
||||
path('key',"The object key you're purchasing (call /content route for available keys)",'string')
|
||||
]
|
||||
action: user.hourglassPurchase
|
||||
|
||||
"/user/inventory/hourglass/mystery/{key}":
|
||||
spec:
|
||||
method: 'POST'
|
||||
description: "Purchase a Mystery Item Set using a Mystic Hourglass"
|
||||
parameters:[
|
||||
path('key',"The key for the Mystery Set you're purchasing (call /content route for available keys)",'string')
|
||||
]
|
||||
action: user.buyMysterySet
|
||||
|
||||
"/user/inventory/feed/{pet}/{food}":
|
||||
spec:
|
||||
|
|
|
|||
|
|
@ -17,12 +17,22 @@
|
|||
.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)')
|
||||
div(ng-repeat='item in set.items')
|
||||
button.customize-option(class='shop_{{::item.key}}',
|
||||
popover='{{::item.notes()}}', popover-title='{{::item.text()}}',
|
||||
popover-trigger='mouseenter', popover-placement='right',
|
||||
popover-append-to-body='true',
|
||||
ng-click='user.ops.buyMysterySet({params:{key:set.key}})')
|
||||
.row
|
||||
.col-md-12
|
||||
li.customize-menu.inventory-gear
|
||||
each prepend, type in {pets:'Pet-', mounts:'Mount_Head_'}
|
||||
menu.pets-menu(label=env.t('#{type}'), ng-if='!hasAllTimeTravelerItemsOfType("#{type}")')
|
||||
div(ng-repeat='(item, text) in Content.timeTravelStable["#{type}"]', style='margin-top:0')
|
||||
button.pet-button(class='#{prepend}{{::item}}', style='margin-top:0',
|
||||
ng-if='!user.items["#{type}"][item]',
|
||||
popover='{{::text()}}', popover-trigger='mouseenter',
|
||||
popover-placement='right', popover-append-to-body='true',
|
||||
ng-click='clickTimeTravelItem("#{type}",item)')
|
||||
li.customize-menu.inventory-gear
|
||||
menu.pets-menu(label='{{::set.text}}', ng-repeat='set in Content.timeTravelerStore(user.items.gear.owned)')
|
||||
div(ng-repeat='item in set.items')
|
||||
button.customize-option(class='shop_{{::item.key}}',
|
||||
popover='{{::item.notes()}}', popover-title='{{::item.text()}}',
|
||||
popover-trigger='mouseenter', popover-placement='right',
|
||||
popover-append-to-body='true',
|
||||
ng-click='user.ops.buyMysterySet({params:{key:set.key}})')
|
||||
|
|
|
|||
|
|
@ -1,32 +1,51 @@
|
|||
h2 CHALLENGE SPOTLIGHT, NEW SOUND THEME, START QUEST BUTTON, AND CUSTOM DAY START FIXES
|
||||
h2 9/16/2015 - MAMMOTHS AND MANTIS SHRIMPS IN TIME TRAVELER SHOP! PLUS, FALL FESTIVAL PLOT-LINE CONTINUES
|
||||
hr
|
||||
tr
|
||||
td
|
||||
h3 Challenge Spotlight
|
||||
p There's a new Challenge Spotlight <a href='https://habitica.wordpress.com/2015/09/12/study-motivation-self-discipline-and-more-september-challenge-spotlight/' target='_blank'>on our blog!</a> Check it out for some great recommended Challenges, including some about studying and self-discipline.
|
||||
p.small.muted by Lemoness
|
||||
p.small.muted Challenges by shanaqui, keyes, White Rose Duelist, and Elo
|
||||
.Pet-MantisShrimp-Base.pull-right
|
||||
.Pet-Mammoth-Base.pull-right
|
||||
h3 Woolly Mammoths and Mantis Shrimps in Time Traveler Shop
|
||||
p The <a href='/#/options/inventory/timetravelers'>Time Travelers</a> have traveled back to Summer 2014 and Winter 2015 to obtain some Mammoth and Mantis Shrimp pets and mounts! You can buy them with Mystic Hourglasses, which are awarded to long-term <a href='/#/options/settings/subscription'>subscribers</a>. Thanks for helping us to keep Habitica running!
|
||||
p.small.muted by SabreCat, Blade, and cheerskevin
|
||||
p.small.muted Art by Ottl and Baconsaur
|
||||
tr
|
||||
td
|
||||
h3 New Sound Theme
|
||||
p There's a new sound effect theme on the site: LuneFox's Theme! Select it from the megaphone in the upper right. It will play sound effects when you click things!
|
||||
p.small.muted by LuneFox and Alys
|
||||
tr
|
||||
td
|
||||
h3 Start Quest Button
|
||||
p Now you can begin a boss fight or collection quest directly from your <a href='/#/options/groups/party'>Party Page</a>! Just click the green Start Quest button on the left. If you already have quest scrolls, they will pop up automatically. Otherwise, it will take you directly to the Quest Shop. Enjoy the added convenience!
|
||||
p.small.muted by SabreCat and cheerskevin
|
||||
tr
|
||||
td
|
||||
h3 Custom Day Start Fixes
|
||||
p The Custom Day Start feature has been fixed so that it can now be changed at any time with complete safety! For those who don't know, this feature enables you to set what time your Dailies will roll over to a new day. To set a Custom Day Start, go to <a href='/#/options/settings/settings'>Settings > Site</a> > Custom Day Start.
|
||||
p.small.muted by carolstone and Blade
|
||||
h3 Fall Festival Plot-Line Continues
|
||||
p Last minute preparations for the Fall Festival are underway! Lemoness has been bustling about with tomes of potion-brewing, and conferring with the artisans in cheerful conspiracy. SabreCat has been seen in the smithy, toiling on projects that he has loudly announced to be "very hush-hush." Even the elusive Royal Chancellor, Redphoenix, has taken a break from sending Boring Business Letters to roast marshmallows outside the Tavern. Everyone has happily gathered around her little campfire, which she is feeding with a steady supply of envelopes.
|
||||
br
|
||||
p Only one thing has disrupted the anticipation. You catch Lemoness frowning as she reads a message attached to the latest shipment from the Flourishing Fields.
|
||||
br
|
||||
p "They're apologizing for not sending as many pumpkins as they promised, due to an 'unanticipated setback,'" she explains. "There's no need for them to be sorry, though -- they've sent us hundreds already! They said the same thing last week about the candy vegetable harvest. I told the Joyful Reaper not to worry about it, but she just promises to work harder."
|
||||
br
|
||||
p Well, soon the Festival will launch, and they'll be able to take a break. Nothing to be concerned about!
|
||||
|
||||
if menuItem !== 'oldNews'
|
||||
hr
|
||||
a(href='/static/old-news', target='_blank') Read older news
|
||||
|
||||
mixin oldNews
|
||||
h2 CHALLENGE SPOTLIGHT, NEW SOUND THEME, START QUEST BUTTON, AND CUSTOM DAY START FIXES
|
||||
tr
|
||||
td
|
||||
h3 Challenge Spotlight
|
||||
p There's a new Challenge Spotlight <a href='https://habitica.wordpress.com/2015/09/12/study-motivation-self-discipline-and-more-september-challenge-spotlight/' target='_blank'>on our blog!</a> Check it out for some great recommended Challenges, including some about studying and self-discipline.
|
||||
p.small.muted by Lemoness
|
||||
p.small.muted Challenges by shanaqui, keyes, White Rose Duelist, and Elo
|
||||
tr
|
||||
td
|
||||
h3 New Sound Theme
|
||||
p There's a new sound effect theme on the site: LuneFox's Theme! Select it from the megaphone in the upper right. It will play sound effects when you click things!
|
||||
p.small.muted by LuneFox and Alys
|
||||
tr
|
||||
td
|
||||
h3 Start Quest Button
|
||||
p Now you can begin a boss fight or collection quest directly from your <a href='/#/options/groups/party'>Party Page</a>! Just click the green Start Quest button on the left. If you already have quest scrolls, they will pop up automatically. Otherwise, it will take you directly to the Quest Shop. Enjoy the added convenience!
|
||||
p.small.muted by SabreCat and cheerskevin
|
||||
tr
|
||||
td
|
||||
h3 Custom Day Start Fixes
|
||||
p The Custom Day Start feature has been fixed so that it can now be changed at any time with complete safety! For those who don't know, this feature enables you to set what time your Dailies will roll over to a new day. To set a Custom Day Start, go to <a href='/#/options/settings/settings'>Settings > Site</a> > Custom Day Start.
|
||||
p.small.muted by carolstone and Blade
|
||||
h2 HORSE PET QUEST, NEW PRODUCTIVITY BLOG, AND FALL PLOT-LINE BEGINS
|
||||
tr
|
||||
td
|
||||
|
|
|
|||
Loading…
Reference in a new issue