diff --git a/package-lock.json b/package-lock.json index e982f05255..d463f85ed0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "habitica", - "version": "4.91.1", + "version": "4.92.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 83c3db5de6..836d394461 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "habitica", "description": "A habit tracker app which treats your goals like a Role Playing Game.", - "version": "4.91.1", + "version": "4.92.0", "main": "./website/server/index.js", "dependencies": { "@google-cloud/trace-agent": "^3.6.0", diff --git a/website/client/assets/css/sprites.css b/website/client/assets/css/sprites.css index 906e3bc5a2..53fe4464fc 100755 --- a/website/client/assets/css/sprites.css +++ b/website/client/assets/css/sprites.css @@ -10,6 +10,12 @@ height: 219px; } +.Pet_HatchingPotion_Veggie { + background: url("~assets/images/Pet_HatchingPotion_Veggie.gif") no-repeat; + width: 68px; + height: 68px; +} + .Gems { display:inline-block; margin-right:5px; diff --git a/website/client/assets/css/sprites/spritesmith-largeSprites-0.css b/website/client/assets/css/sprites/spritesmith-largeSprites-0.css index a02acdf8b7..fff52b63fc 100644 --- a/website/client/assets/css/sprites/spritesmith-largeSprites-0.css +++ b/website/client/assets/css/sprites/spritesmith-largeSprites-0.css @@ -1,21 +1,21 @@ .promo_april_fools_2019 { - background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png'); - background-position: -445px -163px; - width: 423px; - height: 147px; -} -.promo_armoire_backgrounds_201904 { background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png'); background-position: 0px -337px; width: 423px; height: 147px; } -.promo_celestial_rainbow_potions { +.promo_armoire_backgrounds_201904 { background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png'); background-position: -424px -337px; width: 423px; height: 147px; } +.promo_celestial_rainbow_potions { + background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png'); + background-position: -445px -163px; + width: 423px; + height: 147px; +} .promo_classes_spring2019 { background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png'); background-position: -445px 0px; @@ -30,13 +30,13 @@ } .promo_mystery_201903 { background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png'); - background-position: -355px -485px; + background-position: -352px -633px; width: 351px; height: 147px; } .promo_seasonalshop_spring { background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png'); - background-position: -707px -485px; + background-position: -710px -485px; width: 162px; height: 138px; } @@ -46,9 +46,15 @@ width: 351px; height: 147px; } +.promo_spring_avatar_customizations { + background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png'); + background-position: -355px -485px; + width: 354px; + height: 147px; +} .promo_take_this { background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png'); - background-position: -352px -633px; + background-position: -704px -633px; width: 96px; height: 69px; } diff --git a/website/client/assets/images/sprites/spritesmith-largeSprites-0.png b/website/client/assets/images/sprites/spritesmith-largeSprites-0.png index 2467216914..6260927018 100644 Binary files a/website/client/assets/images/sprites/spritesmith-largeSprites-0.png and b/website/client/assets/images/sprites/spritesmith-largeSprites-0.png differ diff --git a/website/client/assets/scss/animals.scss b/website/client/assets/scss/animals.scss index a75f6dcb17..91d3e7acdf 100644 --- a/website/client/assets/scss/animals.scss +++ b/website/client/assets/scss/animals.scss @@ -18,3 +18,7 @@ .Pet.Pet-Dragon-Hydra { top: -16px !important; } + +.Pet.Pet-FlyingPig-Veggie { + top: -28px !important; +} diff --git a/website/client/components/appFooter.vue b/website/client/components/appFooter.vue index 89d12e0ecf..93f8e1766e 100644 --- a/website/client/components/appFooter.vue +++ b/website/client/components/appFooter.vue @@ -45,8 +45,6 @@ a(href='https://www.facebook.com/Habitica', target='_blank') {{ $t('communityFacebook') }} li a(href='https://www.instagram.com/habitica', target='_blank') {{ $t('communityInstagram') }} - li - a(href='https://www.reddit.com/r/habitrpg/', target='_blank') {{ $t('communityReddit') }} .col-12.col-md-6 .row .col-6 diff --git a/website/client/components/inventory/stable/index.vue b/website/client/components/inventory/stable/index.vue index 8e28554320..e4e68ecc0e 100644 --- a/website/client/components/inventory/stable/index.vue +++ b/website/client/components/inventory/stable/index.vue @@ -98,7 +98,7 @@ @click="selectPet(context.item)" ) - .btn.btn-flat.btn-show-more(@click="setShowMore(petGroup.key)", v-if='petGroup.key !== "specialPets"') + .btn.btn-flat.btn-show-more(@click="setShowMore(petGroup.key)", v-if='petGroup.key !== "specialPets" && petGroup.key !== "wackyPets"') | {{ $_openedItemRows_isToggled(petGroup.key) ? $t('showLess') : $t('showMore') }} h2 @@ -462,6 +462,14 @@ potions: this.content.dropHatchingPotions, }, }, + { + label: this.$t('filterByWacky'), + key: 'wackyPets', + petSource: { + eggs: this.content.dropEggs, + potions: this.content.wackyHatchingPotions, + }, + }, { label: this.$t('special'), key: 'specialPets', @@ -661,7 +669,7 @@ let pets = this.listAnimals(animalGroup, 'pet', hideMissing, sortBy, searchText); // Don't group special - if (animalGroup.key === 'specialPets') { + if (animalGroup.key === 'specialPets' || animalGroup.key === 'wackyPets') { return {none: pets}; } diff --git a/website/client/libs/createAnimal.js b/website/client/libs/createAnimal.js index d2f273b3b6..4c0dd8772d 100644 --- a/website/client/libs/createAnimal.js +++ b/website/client/libs/createAnimal.js @@ -2,6 +2,7 @@ import content from 'common/script/content'; const specialPets = Object.keys(content.specialPets); +const wackyPets = Object.keys(content.wackyPets); function getText (textOrFunction) { if (textOrFunction instanceof Function) { @@ -23,6 +24,7 @@ export function isHatchable (animal, userItems) { export function isAllowedToFeed (animal, userItems) { return !specialPets.includes(animal.key) && + !wackyPets.includes(animal.key) && isOwned('pet', animal, userItems) && !isOwned('mount', animal, userItems); } @@ -59,4 +61,3 @@ export function createAnimal (egg, potion, type, _content, userItems) { }, }; } - diff --git a/website/common/locales/en/content.json b/website/common/locales/en/content.json index b30e6eb8e4..8704e77451 100644 --- a/website/common/locales/en/content.json +++ b/website/common/locales/en/content.json @@ -281,6 +281,7 @@ "hatchingPotionIcySnow": "Icy Snow", "hatchingPotionRoseQuartz": "Rose Quartz", "hatchingPotionCelestial": "Celestial", + "hatchingPotionVeggie": "Garden", "hatchingPotionNotes": "Pour this on an egg, and it will hatch as a <%= potText(locale) %> pet.", "premiumPotionAddlNotes": "Not usable on quest pet eggs.", diff --git a/website/common/locales/en/pets.json b/website/common/locales/en/pets.json index 03096ba705..c629c7bd53 100644 --- a/website/common/locales/en/pets.json +++ b/website/common/locales/en/pets.json @@ -7,6 +7,7 @@ "magicPets": "Magic Potion Pets", "rarePets": "Rare Pets", "questPets": "Quest Pets", + "wackyPets": "Wacky Pets", "mounts": "Mounts", "activeMount": "Active Mount", "noActiveMount": "No Active Mount", @@ -129,6 +130,7 @@ "filterByStandard": "Standard", "filterByMagicPotion": "Magic Potion", "filterByQuest": "Quest", + "filterByWacky": "Wacky", "standard": "Standard", "sortByColor": "Color", "sortByHatchable": "Hatchable", diff --git a/website/common/script/content/appearance/sets.js b/website/common/script/content/appearance/sets.js index bc0a53e237..b8fd74b1a4 100644 --- a/website/common/script/content/appearance/sets.js +++ b/website/common/script/content/appearance/sets.js @@ -10,12 +10,12 @@ module.exports = prefill({ winterHairColors: {setPrice: 5, availableUntil: '2016-01-01'}, pastelHairColors: {setPrice: 5, availableUntil: '2016-01-01'}, rainbowHairColors: {setPrice: 5, text: t('rainbowColors')}, - shimmerHairColors: {setPrice: 5, availableFrom: '2018-04-05', availableUntil: '2018-05-02', text: t('shimmerColors')}, + shimmerHairColors: {setPrice: 5, availableFrom: '2019-04-09', availableUntil: '2019-05-02', text: t('shimmerColors')}, hauntedHairColors: {setPrice: 5, availableFrom: '2018-10-11', availableUntil: '2018-11-02', text: t('hauntedColors')}, winteryHairColors: {setPrice: 5, availableFrom: '2019-01-08', availableUntil: '2019-02-02', text: t('winteryColors')}, rainbowSkins: {setPrice: 5, text: t('rainbowSkins')}, animalSkins: {setPrice: 5, text: t('animalSkins')}, - pastelSkins: {setPrice: 5, availableFrom: '2018-04-05', availableUntil: '2018-05-02', text: t('pastelSkins')}, + pastelSkins: {setPrice: 5, availableFrom: '2019-04-09', availableUntil: '2019-05-02', text: t('pastelSkins')}, spookySkins: {setPrice: 5, availableUntil: '2016-01-01', text: t('spookySkins')}, supernaturalSkins: {setPrice: 5, availableFrom: '2018-10-11', availableUntil: '2018-11-02', text: t('supernaturalSkins')}, splashySkins: {setPrice: 5, availableFrom: '2018-07-10', availableUntil: '2018-08-02', text: t('splashySkins')}, diff --git a/website/common/script/content/hatching-potions.js b/website/common/script/content/hatching-potions.js index d4395c8fcb..dfc0790eb3 100644 --- a/website/common/script/content/hatching-potions.js +++ b/website/common/script/content/hatching-potions.js @@ -170,6 +170,14 @@ let premium = { }, }; +const wacky = { + Veggie: { + text: t('hatchingPotionVeggie'), + limited: true, + _season: 'March', + }, +}; + each(drops, (pot, key) => { defaults(pot, { key, @@ -203,10 +211,30 @@ each(premium, (pot, key) => { }); }); -let all = assign({}, drops, premium); +each(wacky, (pot, key) => { + defaults(pot, { + key, + value: 2, + notes: t('hatchingPotionNotes', { + potText: pot.text, + }), + _addlNotes: t('eventAvailability', { + date: t(`dateEnd${pot._season}`), + }), + premium: false, + limited: true, + wacky: true, + canBuy () { + return pot._season === CURRENT_SEASON; + }, + }); +}); + +let all = assign({}, drops, premium, wacky); module.exports = { drops, premium, + wacky, all, }; diff --git a/website/common/script/content/index.js b/website/common/script/content/index.js index 09c8e9fda5..e452f1b4bb 100644 --- a/website/common/script/content/index.js +++ b/website/common/script/content/index.js @@ -356,12 +356,14 @@ api.timeTravelStable = { api.dropHatchingPotions = hatchingPotions.drops; api.premiumHatchingPotions = hatchingPotions.premium; +api.wackyHatchingPotions = hatchingPotions.wacky; api.hatchingPotions = hatchingPotions.all; api.pets = stable.dropPets; api.premiumPets = stable.premiumPets; api.questPets = stable.questPets; api.specialPets = stable.specialPets; +api.wackyPets = stable.wackyPets; api.petInfo = stable.petInfo; api.mounts = stable.dropMounts; diff --git a/website/common/script/content/stable.js b/website/common/script/content/stable.js index 1c758b2714..bee75eea94 100644 --- a/website/common/script/content/stable.js +++ b/website/common/script/content/stable.js @@ -6,6 +6,7 @@ import { import { drops as dropPotions, premium as premiumPotions, + wacky as wackyPotions, } from './hatching-potions'; import t from './translation'; @@ -47,9 +48,38 @@ function constructSet (type, eggs, potions) { return [pets, mounts]; } +function constructPetOnlySet (type, eggs, potions) { + let pets = {}; + + each(eggs, (egg) => { + each(potions, (potion) => { + let key = `${egg.key}-${potion.key}`; + + function getAnimalData (text) { + return { + key, + type, + potion: potion.key, + egg: egg.key, + text, + }; + } + + petInfo[key] = getAnimalData(t('petName', { + potion: potion.text, + egg: egg.text, + })); + pets[key] = true; + }); + }); + + return pets; +} + let [dropPets, dropMounts] = constructSet('drop', dropEggs, dropPotions); let [premiumPets, premiumMounts] = constructSet('premium', dropEggs, premiumPotions); let [questPets, questMounts] = constructSet('quest', questEggs, dropPotions); +let wackyPets = constructPetOnlySet('wacky', dropEggs, wackyPotions); let specialPets = { 'Wolf-Veteran': 'veteranWolf', @@ -113,6 +143,7 @@ module.exports = { dropPets, premiumPets, questPets, + wackyPets, dropMounts, questMounts, premiumMounts, diff --git a/website/common/script/libs/getItemInfo.js b/website/common/script/libs/getItemInfo.js index 151ae0bb28..d4317fc570 100644 --- a/website/common/script/libs/getItemInfo.js +++ b/website/common/script/libs/getItemInfo.js @@ -91,7 +91,7 @@ module.exports = function getItemInfo (user, type, item, officialPinnedItems, la locked: false, currency: 'gems', purchaseType: 'hatchingPotions', - path: `premiumHatchingPotions.${item.key}`, + path: item.wacky ? `wackyHatchingPotions.${item.key}` : `premiumHatchingPotions.${item.key}`, pinType: 'premiumHatchingPotion', }; break; diff --git a/website/raw_sprites/spritesmith_large/promo_spring_avatar_customizations.png b/website/raw_sprites/spritesmith_large/promo_spring_avatar_customizations.png new file mode 100644 index 0000000000..bda1f1c7cd Binary files /dev/null and b/website/raw_sprites/spritesmith_large/promo_spring_avatar_customizations.png differ diff --git a/website/server/controllers/api-v3/news.js b/website/server/controllers/api-v3/news.js index c5bcc25d74..4f51f62b4c 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 = 'NEW BACKGROUNDS AND ARMOIRE ITEMS, MONTHLY CHALLENGES, AND SHINY SEEDS'; +const LAST_ANNOUNCEMENT_TITLE = 'APRIL FOOLS CHALLENGE WINNERS, GARDEN HATCHING POTIONS, AND SPRING AVATAR CUSTOMIZATIONS'; const worldDmg = { // @TODO bailey: false, }; @@ -30,30 +30,25 @@ api.getNews = {
We’ve added three new backgrounds to the Background Shop! Now your avatar can visit a Halfling's House, dally through a peaceful Birch Forest, and take in the Superbloom in the Blossoming Desert. Check them out under User Icon > Backgrounds!
-Plus, there’s new Gold-purchasable equipment in the Enchanted Armoire, including some fun joke props in honor of April Fool's Day! Better work hard on your real-life tasks to earn all the pieces! Enjoy :)
-The Habitica team has launched a special official Challenge series hosted in the Official New Year's Resolution Guild. These Challenges are designed to help you build and maintain goals that are destined for success and then stick with them as the year progresses. For this month's Challenge, Gather Your Party, we're focusing on finding encouraging allies to help you gain accountability for your goals! It has a 15 Gem prize, which will be awarded to five lucky winners on May 1st.
-Congratulations to the winners of March's Challenge, DcryptMart, LONEW0LF, Elcaracol, DungeonMasterful, and 7NationTpr!
- -The next Take This Challenge has also launched, "Harder, Faster, Stronger!", with a focus on setting and meeting physical activity goals. Be sure to check it out to earn additional pieces of the Take This armor set!
-Take This is a nonprofit that seeks to inform the gamer community about mental health issues, to provide education about mental disorders and mental illness prevention, and to reduce the stigma of mental illness.
-Congratulations to the winners of the last Take This Challenge, "Do One Thing Well!": grand prize winner Денис Кадников, and runners-up addone, alihenri, Hemogoblin3991, Kalu_Ienvru, and gabriellamara! Plus, all participants in that Challenge have received a piece of the Take This item set if they hadn't completed it already. It is located in your Rewards column. Enjoy!
-Throw a Shiny Seed at your friends and they will turn into a cheerful flower until their next cron! You can buy the Seeds in the Seasonal Shop for Gold. Plus, if you get transformed by a Shiny Seed, you'll receive the Agricultural Friends badge!
-Don't want to be a flower? Just buy some Petal-Free Potion from your Rewards column to reverse it.
-Shiny Seeds will be available in the Seasonal Shop until April 30th!
-The winners of the April Fool's Social Media Challenge have been selected! Congratulations to: isaaleonardo, Bee_, kitt-haven, alittleofeverything, and Zelah_Meyer!
+Thank you to everyone who shared their awesome pics with their fruit and veggie pets! You can see a fun recap of the shenanigans on our blog. Stay tuned to see what wacky antics the Fool gets up to next year!
+ +The April Fool returns to the Tavern, wearing his trademarked mischievious grin and pulling a wagon whose contents are covered with a colorful cloth.
+"I'm so glad everyone enjoyed my wholesome joke!" he declares, tossing confetti in the air as he often does. "Since you all had so much fun, I've brought you another surprise!"
+He dramatically pulls away the cloth to reveal that the wagon is filled with potion bottles! Each bottle seems to contain a shape-shifting vegetable.
+"Now you can keep your fruit and veggie pets all year round!" he says. "Take good care of them, and I'll see you all again soon. I guess I've really outdone myself so I have some serious planning to do before next year..." With that, the Fool takes his leave, disappearing in a puff of lettuce leaves and leaving the cart full of potions.
+Thanks to the April Fool, you can purchase Garden Magic Hatching Potions in the Market between now and April 30! Garden pets do not have mount forms (yet!) so keep that in mind when you're purchasing. After they're gone, it will be at least a year before Garden Magic Potions are available again, so be sure to get them now!
+The Seasonal Edition Shimmer Hair Colors and Pastel Skin Set are now available for purchase in the User > Edit Avatar! These skin sets will only be available to purchase until April 30th, and then they will disappear from the shop until next Spring Fling. If you buy them, though, you will have access to them year-round!
+