diff --git a/gulp/gulp-sprites.js b/gulp/gulp-sprites.js index 2711537ea4..c232fb475a 100644 --- a/gulp/gulp-sprites.js +++ b/gulp/gulp-sprites.js @@ -16,7 +16,7 @@ const IMG_DIST_PATH = 'website/client/assets/images/sprites/'; const CSS_DIST_PATH = 'website/client/assets/css/sprites/'; function checkForSpecialTreatment (name) { - let regex = /^hair|skin|beard|mustach|shirt|flower|^headAccessory_special_\w+Ears|^eyewear_special_\w+TopFrame/; + let regex = /^hair|skin|beard|mustach|shirt|flower|^headAccessory_special_\w+Ears|^eyewear_special_\w+TopFrame|^eyewear_special_\w+HalfMoon/; return name.match(regex) || name === 'head_0'; } diff --git a/migrations/archive/2019/20190530_halfmoon_glasses.js b/migrations/archive/2019/20190530_halfmoon_glasses.js new file mode 100644 index 0000000000..521da8b5d5 --- /dev/null +++ b/migrations/archive/2019/20190530_halfmoon_glasses.js @@ -0,0 +1,62 @@ +/* eslint-disable no-console */ +const MIGRATION_NAME = '20190530_halfmoon_glasses'; +import { v4 as uuid } from 'uuid'; + +import { model as User } from '../../../website/server/models/user'; + +const progressCount = 1000; +let count = 0; + +async function updateUser (user) { + count++; + + const set = { + 'items.gear.owned.eyewear_special_blackHalfMoon': true, + 'items.gear.owned.eyewear_special_blueHalfMoon': true, + 'items.gear.owned.eyewear_special_greenHalfMoon': true, + 'items.gear.owned.eyewear_special_pinkHalfMoon': true, + 'items.gear.owned.eyewear_special_redHalfMoon': true, + 'items.gear.owned.eyewear_special_whiteHalfMoon': true, + 'items.gear.owned.eyewear_special_yellowHalfMoon': true, + }; + + set.migration = MIGRATION_NAME; + + if (count % progressCount === 0) console.warn(`${count} ${user._id}`); + + return await User.update({_id: user._id}, {$set: set}).exec(); +} + +module.exports = async function processUsers () { + let query = { + migration: {$ne: MIGRATION_NAME}, + 'auth.timestamps.loggedin': {$gt: new Date('2019-05-01')}, + }; + + const fields = { + _id: 1, + items: 1, + }; + + while (true) { // eslint-disable-line no-constant-condition + const users = await User // eslint-disable-line no-await-in-loop + .find(query) + .limit(250) + .sort({_id: 1}) + .select(fields) + .lean() + .exec(); + + if (users.length === 0) { + console.warn('All appropriate users found and modified.'); + console.warn(`\n${count} users processed\n`); + break; + } else { + query._id = { + $gt: users[users.length - 1], + }; + } + + await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop + } +}; diff --git a/test/common/ops/buy/buy.js b/test/common/ops/buy/buy.js index f203ae0cd9..582166e9a9 100644 --- a/test/common/ops/buy/buy.js +++ b/test/common/ops/buy/buy.js @@ -80,6 +80,13 @@ describe('shared.ops.buy', () => { headAccessory_special_redHeadband: true, headAccessory_special_whiteHeadband: true, headAccessory_special_yellowHeadband: true, + eyewear_special_blackHalfMoon: true, + eyewear_special_blueHalfMoon: true, + eyewear_special_greenHalfMoon: true, + eyewear_special_pinkHalfMoon: true, + eyewear_special_redHalfMoon: true, + eyewear_special_whiteHalfMoon: true, + eyewear_special_yellowHalfMoon: true, }); }); diff --git a/test/common/ops/buy/buyMarketGear.js b/test/common/ops/buy/buyMarketGear.js index 602975f6a6..a732afa4e0 100644 --- a/test/common/ops/buy/buyMarketGear.js +++ b/test/common/ops/buy/buyMarketGear.js @@ -75,6 +75,13 @@ describe('shared.ops.buyMarketGear', () => { headAccessory_special_redHeadband: true, headAccessory_special_whiteHeadband: true, headAccessory_special_yellowHeadband: true, + eyewear_special_blackHalfMoon: true, + eyewear_special_blueHalfMoon: true, + eyewear_special_greenHalfMoon: true, + eyewear_special_pinkHalfMoon: true, + eyewear_special_redHalfMoon: true, + eyewear_special_whiteHalfMoon: true, + eyewear_special_yellowHalfMoon: true, }); expect(analytics.track).to.be.calledOnce; }); diff --git a/website/client/components/creatorIntro.vue b/website/client/components/creatorIntro.vue index 30f94426eb..b38986d598 100644 --- a/website/client/components/creatorIntro.vue +++ b/website/client/components/creatorIntro.vue @@ -87,7 +87,7 @@ b-modal#avatar-modal(title="", :size='editing ? "lg" : "md"', :hide-header='true button.btn.btn-secondary.purchase-all(@click='unlock(`skin.${set.keys.join(",skin.")}`)') {{ $t('purchaseAll') }} #hair.section.customize-section(v-if='activeTopPage === "hair"') .row.col-12.sub-menu.text-center - .col-3.text-center.sub-menu-item(@click='changeSubPage("color")', :class='{active: activeSubPage === "color"}') + .col-3.text-center.sub-menu-item(@click='changeSubPage("color")', :class='{active: activeSubPage === "color", "offset-2": !editing}') strong(v-once) {{$t('color')}} .col-3.text-center.sub-menu-item(@click='changeSubPage("bangs")', :class='{active: activeSubPage === "bangs"}') strong(v-once) {{$t('bangs')}} @@ -139,6 +139,7 @@ b-modal#avatar-modal(title="", :size='editing ? "lg" : "md"', :hide-header='true span 5 button.btn.btn-secondary.purchase-all(@click='unlock(`hair.base.${baseHair4Keys.join(",hair.base.")}`)') {{ $t('purchaseAll') }} .col-12.customize-options + .head_0.option(v-if="!editing", @click='set({"preferences.hair.base": 0})', :class="[{ active: user.preferences.hair.base === 0 }, 'hair_base_0_' + user.preferences.hair.color]") .option(v-for='option in baseHair1', :class='{active: user.preferences.hair.base === option}') .base.sprite.customize-option(:class="`hair_base_${option}_${user.preferences.hair.color}`", @click='set({"preferences.hair.base": option})') @@ -1125,7 +1126,10 @@ export default { return options; }, eyewear () { - let keys = ['blackTopFrame', 'blueTopFrame', 'greenTopFrame', 'pinkTopFrame', 'redTopFrame', 'whiteTopFrame', 'yellowTopFrame']; + let keys = [ + 'blackTopFrame', 'blueTopFrame', 'greenTopFrame', 'pinkTopFrame', 'redTopFrame', 'whiteTopFrame', 'yellowTopFrame', + 'blackHalfMoon', 'blueHalfMoon', 'greenHalfMoon', 'pinkHalfMoon', 'redHalfMoon', 'whiteHalfMoon', 'yellowHalfMoon', + ]; let options = keys.map(key => { let newKey = `eyewear_special_${key}`; let option = {}; diff --git a/website/common/locales/en/gear.json b/website/common/locales/en/gear.json index 0cfe55763f..4f8eead30d 100644 --- a/website/common/locales/en/gear.json +++ b/website/common/locales/en/gear.json @@ -1938,6 +1938,21 @@ "eyewearSpecialYellowTopFrameText": "Yellow Standard Eyeglasses", "eyewearSpecialYellowTopFrameNotes": "Glasses with a yellow frame above the lenses. Confers no benefit.", + "eyewearSpecialBlackHalfMoonText": "Black Half-Moon Eyeglasses", + "eyewearSpecialBlackHalfMoonNotes": "Glasses with a black frame and crescent lenses. Confers no benefit.", + "eyewearSpecialBlueHalfMoonText": "Blue Half-Moon Eyeglasses", + "eyewearSpecialBlueHalfMoonNotes": "Glasses with a blue frame and crescent lenses. Confers no benefit.", + "eyewearSpecialGreenHalfMoonText": "Green Half-Moon Eyeglasses", + "eyewearSpecialGreenHalfMoonNotes": "Glasses with a green frame and crescent lenses. Confers no benefit.", + "eyewearSpecialPinkHalfMoonText": "Pink Half-Moon Eyeglasses", + "eyewearSpecialPinkHalfMoonNotes": "Glasses with a pink frame and crescent lenses. Confers no benefit.", + "eyewearSpecialRedHalfMoonText": "Red Half-Moon Eyeglasses", + "eyewearSpecialRedHalfMoonNotes": "Glasses with a red frame and crescent lenses. Confers no benefit.", + "eyewearSpecialWhiteHalfMoonText": "White Half-Moon Eyeglasses", + "eyewearSpecialWhiteHalfMoonNotes": "Glasses with a white frame and crescent lenses. Confers no benefit.", + "eyewearSpecialYellowHalfMoonText": "Yellow Half-Moon Eyeglasses", + "eyewearSpecialYellowHalfMoonNotes": "Glasses with a yellow frame and crescent lenses. Confers no benefit.", + "eyewearSpecialAetherMaskText": "Aether Mask", "eyewearSpecialAetherMaskNotes": "This mask has a mysterious history. Increases Intelligence by <%= int %>.", diff --git a/website/common/script/content/gear/sets/special/index.js b/website/common/script/content/gear/sets/special/index.js index af2caf0ebd..2afc8aef05 100644 --- a/website/common/script/content/gear/sets/special/index.js +++ b/website/common/script/content/gear/sets/special/index.js @@ -1441,6 +1441,55 @@ let eyewear = { int: 10, canOwn: ownsItem('eyewear_special_aetherMask'), }, + blackHalfMoon: { + gearSet: 'glasses', + text: t('eyewearSpecialBlackHalfMoonText'), + notes: t('eyewearSpecialBlackHalfMoonNotes'), + value: 0, + canOwn: ownsItem('eyewear_special_blackHalfMoon'), + }, + blueHalfMoon: { + gearSet: 'glasses', + text: t('eyewearSpecialBlueHalfMoonText'), + notes: t('eyewearSpecialBlueHalfMoonNotes'), + value: 0, + canOwn: ownsItem('eyewear_special_blueHalfMoon'), + }, + greenHalfMoon: { + gearSet: 'glasses', + text: t('eyewearSpecialGreenHalfMoonText'), + notes: t('eyewearSpecialGreenHalfMoonNotes'), + value: 0, + canOwn: ownsItem('eyewear_special_greenHalfMoon'), + }, + pinkHalfMoon: { + gearSet: 'glasses', + text: t('eyewearSpecialPinkHalfMoonText'), + notes: t('eyewearSpecialPinkHalfMoonNotes'), + value: 0, + canOwn: ownsItem('eyewear_special_pinkHalfMoon'), + }, + redHalfMoon: { + gearSet: 'glasses', + text: t('eyewearSpecialRedHalfMoonText'), + notes: t('eyewearSpecialRedHalfMoonNotes'), + value: 0, + canOwn: ownsItem('eyewear_special_redHalfMoon'), + }, + whiteHalfMoon: { + gearSet: 'glasses', + text: t('eyewearSpecialWhiteHalfMoonText'), + notes: t('eyewearSpecialWhiteHalfMoonNotes'), + value: 0, + canOwn: ownsItem('eyewear_special_whiteHalfMoon'), + }, + yellowHalfMoon: { + gearSet: 'glasses', + text: t('eyewearSpecialYellowHalfMoonText'), + notes: t('eyewearSpecialYellowHalfMoonNotes'), + value: 0, + canOwn: ownsItem('eyewear_special_yellowHalfMoon'), + }, }; let head = { diff --git a/website/raw_sprites/spritesmith/gear/eyewear/eyewear_special_blackHalfMoon.png b/website/raw_sprites/spritesmith/gear/eyewear/eyewear_special_blackHalfMoon.png new file mode 100644 index 0000000000..e02a483318 Binary files /dev/null and b/website/raw_sprites/spritesmith/gear/eyewear/eyewear_special_blackHalfMoon.png differ diff --git a/website/raw_sprites/spritesmith/gear/eyewear/eyewear_special_blueHalfMoon.png b/website/raw_sprites/spritesmith/gear/eyewear/eyewear_special_blueHalfMoon.png new file mode 100644 index 0000000000..de7d91bc17 Binary files /dev/null and b/website/raw_sprites/spritesmith/gear/eyewear/eyewear_special_blueHalfMoon.png differ diff --git a/website/raw_sprites/spritesmith/gear/eyewear/eyewear_special_greenHalfMoon.png b/website/raw_sprites/spritesmith/gear/eyewear/eyewear_special_greenHalfMoon.png new file mode 100644 index 0000000000..769e8b42fd Binary files /dev/null and b/website/raw_sprites/spritesmith/gear/eyewear/eyewear_special_greenHalfMoon.png differ diff --git a/website/raw_sprites/spritesmith/gear/eyewear/eyewear_special_pinkHalfMoon.png b/website/raw_sprites/spritesmith/gear/eyewear/eyewear_special_pinkHalfMoon.png new file mode 100644 index 0000000000..ea8a8c8882 Binary files /dev/null and b/website/raw_sprites/spritesmith/gear/eyewear/eyewear_special_pinkHalfMoon.png differ diff --git a/website/raw_sprites/spritesmith/gear/eyewear/eyewear_special_redHalfMoon.png b/website/raw_sprites/spritesmith/gear/eyewear/eyewear_special_redHalfMoon.png new file mode 100644 index 0000000000..4af5dd8e6e Binary files /dev/null and b/website/raw_sprites/spritesmith/gear/eyewear/eyewear_special_redHalfMoon.png differ diff --git a/website/raw_sprites/spritesmith/gear/eyewear/eyewear_special_whiteHalfMoon.png b/website/raw_sprites/spritesmith/gear/eyewear/eyewear_special_whiteHalfMoon.png new file mode 100644 index 0000000000..bed581531b Binary files /dev/null and b/website/raw_sprites/spritesmith/gear/eyewear/eyewear_special_whiteHalfMoon.png differ diff --git a/website/raw_sprites/spritesmith/gear/eyewear/eyewear_special_yellowHalfMoon.png b/website/raw_sprites/spritesmith/gear/eyewear/eyewear_special_yellowHalfMoon.png new file mode 100644 index 0000000000..f8f10e88fe Binary files /dev/null and b/website/raw_sprites/spritesmith/gear/eyewear/eyewear_special_yellowHalfMoon.png differ diff --git a/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_blackHalfMoon.png b/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_blackHalfMoon.png new file mode 100644 index 0000000000..ab1858903f Binary files /dev/null and b/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_blackHalfMoon.png differ diff --git a/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_blackTopFrame.png b/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_blackTopFrame.png index 6646cf7f4b..ac07fb432b 100755 Binary files a/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_blackTopFrame.png and b/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_blackTopFrame.png differ diff --git a/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_blueHalfMoon.png b/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_blueHalfMoon.png new file mode 100644 index 0000000000..3fe8c103bd Binary files /dev/null and b/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_blueHalfMoon.png differ diff --git a/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_blueTopFrame.png b/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_blueTopFrame.png index 4c84b23e91..114021b0a4 100755 Binary files a/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_blueTopFrame.png and b/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_blueTopFrame.png differ diff --git a/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_greenHalfMoon.png b/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_greenHalfMoon.png new file mode 100644 index 0000000000..b425dd6e1f Binary files /dev/null and b/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_greenHalfMoon.png differ diff --git a/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_greenTopFrame.png b/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_greenTopFrame.png index be2c4094eb..ddbb2fb6d0 100755 Binary files a/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_greenTopFrame.png and b/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_greenTopFrame.png differ diff --git a/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_pinkHalfMoon.png b/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_pinkHalfMoon.png new file mode 100644 index 0000000000..2dc5828cfa Binary files /dev/null and b/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_pinkHalfMoon.png differ diff --git a/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_pinkTopFrame.png b/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_pinkTopFrame.png index e48b611016..a33775aea5 100755 Binary files a/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_pinkTopFrame.png and b/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_pinkTopFrame.png differ diff --git a/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_redHalfMoon.png b/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_redHalfMoon.png new file mode 100644 index 0000000000..31b9d512c5 Binary files /dev/null and b/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_redHalfMoon.png differ diff --git a/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_redTopFrame.png b/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_redTopFrame.png index ba15fd434b..7802be2655 100755 Binary files a/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_redTopFrame.png and b/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_redTopFrame.png differ diff --git a/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_whiteHalfMoon.png b/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_whiteHalfMoon.png new file mode 100644 index 0000000000..3b0633f7b5 Binary files /dev/null and b/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_whiteHalfMoon.png differ diff --git a/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_whiteTopFrame.png b/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_whiteTopFrame.png index d03be695f9..e58323e755 100755 Binary files a/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_whiteTopFrame.png and b/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_whiteTopFrame.png differ diff --git a/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_yellowHalfMoon.png b/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_yellowHalfMoon.png new file mode 100644 index 0000000000..e41315515e Binary files /dev/null and b/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_yellowHalfMoon.png differ diff --git a/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_yellowTopFrame.png b/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_yellowTopFrame.png index fa2315eed4..8f43b8ebb7 100755 Binary files a/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_yellowTopFrame.png and b/website/raw_sprites/spritesmith/gear/eyewear/shop/shop_eyewear_special_yellowTopFrame.png differ diff --git a/website/raw_sprites/spritesmith_large/promo_halfmoon_glasses.png b/website/raw_sprites/spritesmith_large/promo_halfmoon_glasses.png new file mode 100644 index 0000000000..5276f2458d Binary files /dev/null and b/website/raw_sprites/spritesmith_large/promo_halfmoon_glasses.png differ diff --git a/website/raw_sprites/spritesmith_large/scene_gold.png b/website/raw_sprites/spritesmith_large/scene_gold.png deleted file mode 100644 index ddb4268f0a..0000000000 Binary files a/website/raw_sprites/spritesmith_large/scene_gold.png and /dev/null differ diff --git a/website/raw_sprites/spritesmith_large/scene_languages.png b/website/raw_sprites/spritesmith_large/scene_languages.png deleted file mode 100644 index d05dcca41c..0000000000 Binary files a/website/raw_sprites/spritesmith_large/scene_languages.png and /dev/null differ diff --git a/website/raw_sprites/spritesmith_large/scene_rewards.png b/website/raw_sprites/spritesmith_large/scene_rewards.png deleted file mode 100644 index 61e6717fae..0000000000 Binary files a/website/raw_sprites/spritesmith_large/scene_rewards.png and /dev/null differ diff --git a/website/raw_sprites/spritesmith_large/scene_spells.png b/website/raw_sprites/spritesmith_large/scene_spells.png deleted file mode 100644 index ecdf7f70de..0000000000 Binary files a/website/raw_sprites/spritesmith_large/scene_spells.png and /dev/null differ diff --git a/website/raw_sprites/spritesmith_large/scene_yesterdailies_repeatables.png b/website/raw_sprites/spritesmith_large/scene_yesterdailies_repeatables.png deleted file mode 100644 index d6218704ff..0000000000 Binary files a/website/raw_sprites/spritesmith_large/scene_yesterdailies_repeatables.png and /dev/null differ diff --git a/website/server/controllers/api-v3/news.js b/website/server/controllers/api-v3/news.js index 317d2e28b3..4e2158cf51 100644 --- a/website/server/controllers/api-v3/news.js +++ b/website/server/controllers/api-v3/news.js @@ -3,7 +3,7 @@ import { authWithHeaders } from '../../middlewares/auth'; let api = {}; // @TODO export this const, cannot export it from here because only routes are exported from controllers -const LAST_ANNOUNCEMENT_TITLE = 'MAY SUBSCRIBER ITEMS REVEALED!'; +const LAST_ANNOUNCEMENT_TITLE = 'NEW GLASSES OPTION FOR AVATARS AND LAST CHANCE FOR MAY LIMITED-TIME ITEMS'; const worldDmg = { // @TODO bailey: false, }; @@ -30,14 +30,29 @@ api.getNews = {
We have a new set of free avatar customizations available: half-moon glasses! We hope that all you glasses-wearing Habiticans out there will enjoy these new options. You can find them in User>Edit Avatar>Extras.
+The May Subscriber Item has been revealed: the Dazzling Dragon Item Set! You only have until May 31 to receive the item set when you subscribe. If you're already an active subscriber, reload the site and then head to Inventory > Items to claim your gear!
-Subscribers also receive the ability to buy Gems for Gold -- the longer you subscribe, the more Gems you can buy per month! There are other perks as well, such as longer access to uncompressed data and a cute Jackalope pet. Best of all, subscriptions let us keep Habitica running. Thank you very much for your support -- it means a lot to us.
-Reminder: tomorrow is the final day to subscribe and receive the Dazzling Dragon Set! Subscribing also lets you buy Gems with Gold. The longer your subscription, the more Gems you get!
+Thanks so much for your support! You help keep Habitica running.
+Reminder: tomorrow is the final day to buy Sunshine and Floral Hatching Potions! If they come back, it won't be until next year at the earliest, so don't delay!
+Tomorrow is also the final day to buy the discounted Feathered Friends Pet Quest Bundle, featuring the Falcon, Parrot, and Owl quests all for seven Gems! Be sure to get a few in your talons before they fly away! The bundle can be found in the Quest Shop.
+