diff --git a/migrations/archive/2021/20210216_pet_group_achievements.js b/migrations/archive/2021/20210216_pet_group_achievements.js new file mode 100644 index 0000000000..6970a4a152 --- /dev/null +++ b/migrations/archive/2021/20210216_pet_group_achievements.js @@ -0,0 +1,108 @@ +/* eslint-disable no-console */ +const MIGRATION_NAME = '20210216_pet_group_achievements'; +import { model as User } from '../../../website/server/models/user'; + +const progressCount = 1000; +let count = 0; + +async function updateUser (user) { + count++; + + const set = { + migration: MIGRATION_NAME, + }; + + if (user && user.items && user.items.pets) { + const pets = user.items.pets; + if (pets['Dragon-Base'] + && pets['Dragon-CottonCandyBlue'] + && pets['Dragon-CottonCandyPink'] + && pets['Dragon-Desert'] + && pets['Dragon-Golden'] + && pets['Dragon-Red'] + && pets['Dragon-Shade'] + && pets['Dragon-Skeleton'] + && pets['Dragon-White'] + && pets['Dragon-Zombie'] + && pets['FlyingPig-Base'] + && pets['FlyingPig-CottonCandyBlue'] + && pets['FlyingPig-CottonCandyPink'] + && pets['FlyingPig-Desert'] + && pets['FlyingPig-Golden'] + && pets['FlyingPig-Red'] + && pets['FlyingPig-Shade'] + && pets['FlyingPig-Skeleton'] + && pets['FlyingPig-White'] + && pets['FlyingPig-Zombie'] + && pets['Gryphon-Base'] + && pets['Gryphon-CottonCandyBlue'] + && pets['Gryphon-CottonCandyPink'] + && pets['Gryphon-Desert'] + && pets['Gryphon-Golden'] + && pets['Gryphon-Red'] + && pets['Gryphon-Shade'] + && pets['Gryphon-Skeleton'] + && pets['Gryphon-White'] + && pets['Gryphon-Zombie'] + && pets['SeaSerpent-Base'] + && pets['SeaSerpent-CottonCandyBlue'] + && pets['SeaSerpent-CottonCandyPink'] + && pets['SeaSerpent-Desert'] + && pets['SeaSerpent-Golden'] + && pets['SeaSerpent-Red'] + && pets['SeaSerpent-Shade'] + && pets['SeaSerpent-Skeleton'] + && pets['SeaSerpent-White'] + && pets['SeaSerpent-Zombie'] + && pets['Unicorn-Base'] + && pets['Unicorn-CottonCandyBlue'] + && pets['Unicorn-CottonCandyPink'] + && pets['Unicorn-Desert'] + && pets['Unicorn-Golden'] + && pets['Unicorn-Red'] + && pets['Unicorn-Shade'] + && pets['Unicorn-Skeleton'] + && pets['Unicorn-White'] + && pets['Unicorn-Zombie']) { + set['achievements.legendaryBestiary'] = true; + } + } + + if (count % progressCount === 0) console.warn(`${count} ${user._id}`); + + return await User.update({ _id: user._id }, { $set: set }).exec(); +} + +export default async function processUsers () { + let query = { + migration: { $ne: MIGRATION_NAME }, + 'auth.timestamps.loggedin': { $gt: new Date('2021-02-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]._id, + }; + } + + await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop + } +}; diff --git a/migrations/migration-runner.js b/migrations/migration-runner.js index 7e3f097190..c66ac2014a 100644 --- a/migrations/migration-runner.js +++ b/migrations/migration-runner.js @@ -18,7 +18,7 @@ function setUpServer () { setUpServer(); // Replace this with your migration -const processUsers = require('./archive/2021/20210129_habit_birthday').default; +const processUsers = require().default; processUsers() .then(() => { diff --git a/website/client/src/assets/css/sprites/spritesmith-main-0.css b/website/client/src/assets/css/sprites/spritesmith-main-0.css index d6a5bc3c05..efa951efd7 100644 --- a/website/client/src/assets/css/sprites/spritesmith-main-0.css +++ b/website/client/src/assets/css/sprites/spritesmith-main-0.css @@ -1,48 +1,48 @@ .achievement-alien { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1659px -1480px; + background-position: -1671px -1480px; width: 24px; height: 26px; } .achievement-alien2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -480px -1549px; + background-position: -529px -1549px; width: 48px; height: 52px; } .achievement-allThatGlitters2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -812px -1480px; + background-position: -873px -1480px; width: 64px; height: 56px; } .achievement-allYourBase2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -877px -1480px; + background-position: -938px -1480px; width: 64px; height: 56px; } .achievement-alpha2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -529px -1549px; + background-position: -578px -1549px; width: 48px; height: 52px; } .achievement-aridAuthority2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -942px -1480px; + background-position: -1003px -1480px; width: 64px; height: 56px; } .achievement-armor2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -578px -1549px; + background-position: -627px -1549px; width: 48px; height: 52px; } .achievement-backToBasics2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1267px -1480px; + background-position: -1328px -1480px; width: 48px; height: 56px; } @@ -54,31 +54,31 @@ } .achievement-bewilder2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -627px -1549px; + background-position: -676px -1549px; width: 48px; height: 52px; } .achievement-birthday2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -676px -1549px; + background-position: -725px -1549px; width: 48px; height: 52px; } .achievement-boneCollector2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1316px -1480px; + background-position: -1377px -1480px; width: 48px; height: 56px; } .achievement-boot2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -725px -1549px; + background-position: -774px -1549px; width: 48px; height: 52px; } .achievement-bow2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -774px -1549px; + background-position: -823px -1549px; width: 48px; height: 52px; } @@ -90,85 +90,85 @@ } .achievement-burnout2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -823px -1549px; + background-position: -872px -1549px; width: 48px; height: 52px; } .achievement-cactus2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -872px -1549px; + background-position: -921px -1549px; width: 48px; height: 52px; } .achievement-cake2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -921px -1549px; + background-position: -970px -1549px; width: 48px; height: 52px; } .achievement-cave2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -970px -1549px; + background-position: -1019px -1549px; width: 48px; height: 52px; } .achievement-challenge2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1019px -1549px; + background-position: -1068px -1549px; width: 48px; height: 52px; } .achievement-comment2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1068px -1549px; + background-position: -1117px -1549px; width: 48px; height: 52px; } .achievement-completedTask2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1365px -1480px; + background-position: -1426px -1480px; width: 48px; height: 56px; } .achievement-congrats2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1117px -1549px; + background-position: -1166px -1549px; width: 48px; height: 52px; } .achievement-costumeContest2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1166px -1549px; + background-position: -1215px -1549px; width: 48px; height: 52px; } .achievement-createdTask2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1414px -1480px; + background-position: -1475px -1480px; width: 48px; height: 56px; } .achievement-dilatory2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1215px -1549px; + background-position: -1264px -1549px; width: 48px; height: 52px; } .achievement-dustDevil2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1463px -1480px; + background-position: -1524px -1480px; width: 48px; height: 56px; } .achievement-dysheartener2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1264px -1549px; + background-position: -1313px -1549px; width: 48px; height: 52px; } .achievement-fedPet2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1512px -1480px; + background-position: -1573px -1480px; width: 48px; height: 56px; } @@ -180,61 +180,61 @@ } .achievement-friends2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1313px -1549px; + background-position: -1362px -1549px; width: 48px; height: 52px; } .achievement-getwell2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1362px -1549px; + background-position: -1411px -1549px; width: 48px; height: 52px; } .achievement-goodAsGold2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1561px -1480px; + background-position: -1622px -1480px; width: 48px; height: 56px; } .achievement-goodluck2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1411px -1549px; + background-position: -1460px -1549px; width: 48px; height: 52px; } .achievement-greeting2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1460px -1549px; + background-position: -1509px -1549px; width: 48px; height: 52px; } .achievement-guild2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1509px -1549px; + background-position: -1558px -1549px; width: 48px; height: 52px; } .achievement-habitBirthday2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1558px -1549px; + background-position: -1607px -1549px; width: 48px; height: 52px; } .achievement-habiticaDay2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1607px -1549px; + background-position: 0px -1628px; width: 48px; height: 52px; } .achievement-hatchedPet2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1610px -1480px; + background-position: -284px -1549px; width: 48px; height: 56px; } .achievement-heart2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: 0px -1628px; + background-position: -49px -1628px; width: 48px; height: 52px; } @@ -246,13 +246,13 @@ } .achievement-karaoke-2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -49px -1628px; + background-position: -98px -1628px; width: 48px; height: 52px; } .achievement-karaoke { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1659px -1507px; + background-position: -1671px -1507px; width: 24px; height: 26px; } @@ -262,87 +262,93 @@ width: 68px; height: 68px; } -.achievement-lostMasterclasser2x { - background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -98px -1628px; - width: 48px; - height: 52px; -} -.achievement-mindOverMatter2x { +.achievement-legendaryBestiary2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); background-position: -751px -1480px; width: 60px; height: 64px; } -.achievement-monsterMagus2x { - background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -284px -1549px; - width: 48px; - height: 56px; -} -.achievement-ninja2x { +.achievement-lostMasterclasser2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); background-position: -147px -1628px; width: 48px; height: 52px; } -.achievement-npc2x { +.achievement-mindOverMatter2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -196px -1628px; - width: 48px; - height: 52px; + background-position: -812px -1480px; + width: 60px; + height: 64px; } -.achievement-nye2x { - background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -245px -1628px; - width: 48px; - height: 52px; -} -.achievement-partyOn2x { - background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -294px -1628px; - width: 48px; - height: 52px; -} -.achievement-partyUp2x { - background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -343px -1628px; - width: 48px; - height: 52px; -} -.achievement-pearlyPro2x { - background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1007px -1480px; - width: 64px; - height: 56px; -} -.achievement-perfect2x { - background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -392px -1628px; - width: 48px; - height: 52px; -} -.achievement-primedForPainting2x { +.achievement-monsterMagus2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); background-position: -333px -1549px; width: 48px; height: 56px; } -.achievement-purchasedEquipment2x { +.achievement-ninja2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -382px -1549px; + background-position: -196px -1628px; width: 48px; + height: 52px; +} +.achievement-npc2x { + background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); + background-position: -245px -1628px; + width: 48px; + height: 52px; +} +.achievement-nye2x { + background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); + background-position: -294px -1628px; + width: 48px; + height: 52px; +} +.achievement-partyOn2x { + background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); + background-position: -343px -1628px; + width: 48px; + height: 52px; +} +.achievement-partyUp2x { + background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); + background-position: -392px -1628px; + width: 48px; + height: 52px; +} +.achievement-pearlyPro2x { + background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); + background-position: -1068px -1480px; + width: 64px; height: 56px; } -.achievement-rat2x { +.achievement-perfect2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); background-position: -441px -1628px; width: 48px; height: 52px; } +.achievement-primedForPainting2x { + background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); + background-position: -382px -1549px; + width: 48px; + height: 56px; +} +.achievement-purchasedEquipment2x { + background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); + background-position: -431px -1549px; + width: 48px; + height: 56px; +} +.achievement-rat2x { + background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); + background-position: -490px -1628px; + width: 48px; + height: 52px; +} .achievement-redLetterDay2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1072px -1480px; + background-position: -1133px -1480px; width: 64px; height: 56px; } @@ -354,79 +360,79 @@ } .achievement-royally-loyal2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -490px -1628px; + background-position: -539px -1628px; width: 48px; height: 52px; } .achievement-seafoam2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -539px -1628px; + background-position: -588px -1628px; width: 48px; height: 52px; } .achievement-seeingRed2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -431px -1549px; + background-position: -480px -1549px; width: 48px; height: 56px; } .achievement-shield2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -588px -1628px; + background-position: -637px -1628px; width: 48px; height: 52px; } .achievement-shinySeed2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -637px -1628px; + background-position: -686px -1628px; width: 48px; height: 52px; } .achievement-skeletonCrew2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1137px -1480px; + background-position: -1198px -1480px; width: 64px; height: 56px; } .achievement-snowball2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -686px -1628px; + background-position: -735px -1628px; width: 48px; height: 52px; } .achievement-spookySparkles2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -735px -1628px; + background-position: -784px -1628px; width: 48px; height: 52px; } .achievement-stoikalm2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -784px -1628px; + background-position: -833px -1628px; width: 48px; height: 52px; } .achievement-sun2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -833px -1628px; + background-position: -882px -1628px; width: 48px; height: 52px; } .achievement-sword2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -882px -1628px; + background-position: -931px -1628px; width: 48px; height: 52px; } .achievement-thankyou2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -931px -1628px; + background-position: -980px -1628px; width: 48px; height: 52px; } .achievement-thermometer2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -980px -1628px; + background-position: -1029px -1628px; width: 48px; height: 52px; } @@ -438,61 +444,61 @@ } .achievement-tree2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1029px -1628px; + background-position: -1078px -1628px; width: 48px; height: 52px; } .achievement-triadbingo2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1078px -1628px; + background-position: -1127px -1628px; width: 48px; height: 52px; } .achievement-ultimate-healer2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1127px -1628px; + background-position: -1176px -1628px; width: 48px; height: 52px; } .achievement-ultimate-mage2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1176px -1628px; + background-position: -1225px -1628px; width: 48px; height: 52px; } .achievement-ultimate-rogue2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1225px -1628px; + background-position: -1274px -1628px; width: 48px; height: 52px; } .achievement-ultimate-warrior2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1274px -1628px; + background-position: -1323px -1628px; width: 48px; height: 52px; } .achievement-undeadUndertaker2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1202px -1480px; + background-position: -1263px -1480px; width: 64px; height: 56px; } .achievement-unearned2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1323px -1628px; + background-position: -1372px -1628px; width: 48px; height: 52px; } .achievement-valentine2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1372px -1628px; + background-position: -1421px -1628px; width: 48px; height: 52px; } .achievement-wolf2x { background-image: url('~@/assets/images/sprites/spritesmith-main-0.png'); - background-position: -1421px -1628px; + background-position: -1470px -1628px; width: 48px; height: 52px; } diff --git a/website/client/src/assets/images/sprites/spritesmith-main-0.png b/website/client/src/assets/images/sprites/spritesmith-main-0.png index 09302ee7b2..ceed17fce1 100644 Binary files a/website/client/src/assets/images/sprites/spritesmith-main-0.png and b/website/client/src/assets/images/sprites/spritesmith-main-0.png differ diff --git a/website/client/src/components/notifications.vue b/website/client/src/components/notifications.vue index d46030a9b5..936f053285 100644 --- a/website/client/src/components/notifications.vue +++ b/website/client/src/components/notifications.vue @@ -386,6 +386,14 @@ const NOTIFICATIONS = { achievement: 'redLetterDay', }, }, + ACHIEVEMENT_LEGENDARY_BESTIARY: { + achievement: true, + label: $t => `${$t('achievement')}: ${$t('achievementLegendaryBestiary')}`, + modalId: 'generic-achievement', + data: { + achievement: 'legendaryBestiary', + }, + }, }; export default { @@ -448,7 +456,7 @@ export default { 'ONBOARDING_COMPLETE', 'FIRST_DROPS', 'ACHIEVEMENT_BUG_BONANZA', 'ACHIEVEMENT_BARE_NECESSITIES', 'ACHIEVEMENT_FRESHWATER_FRIENDS', 'ACHIEVEMENT_GOOD_AS_GOLD', 'ACHIEVEMENT_ALL_THAT_GLITTERS', 'ACHIEVEMENT_BONE_COLLECTOR', 'ACHIEVEMENT_SKELETON_CREW', 'ACHIEVEMENT_SEEING_RED', - 'ACHIEVEMENT_RED_LETTER_DAY', + 'ACHIEVEMENT_RED_LETTER_DAY', 'ACHIEVEMENT_LEGENDARY_BESTIARY', ].forEach(type => { handledNotifications[type] = true; }); @@ -869,6 +877,7 @@ export default { case 'ACHIEVEMENT_SKELETON_CREW': case 'ACHIEVEMENT_SEEING_RED': case 'ACHIEVEMENT_RED_LETTER_DAY': + case 'ACHIEVEMENT_LEGENDARY_BESTIARY': case 'GENERIC_ACHIEVEMENT': this.showNotificationWithModal(notification); break; diff --git a/website/common/locales/en/achievements.json b/website/common/locales/en/achievements.json index 6f7b0af5f8..bb7e5bfd3e 100644 --- a/website/common/locales/en/achievements.json +++ b/website/common/locales/en/achievements.json @@ -102,5 +102,8 @@ "achievementSeeingRedModalText": "You collected all the Red Pets!", "achievementRedLetterDay": "Red Letter Day", "achievementRedLetterDayText": "Has tamed all Red Mounts.", - "achievementRedLetterDayModalText": "You tamed all the Red Mounts!" + "achievementRedLetterDayModalText": "You tamed all the Red Mounts!", + "achievementLegendaryBestiary": "Legendary Bestiary", + "achievementLegendaryBestiaryText": "Has hatched all the mythical pets: Dragon, Flying Pig, Gryphon, Sea Serpent, and Unicorn!", + "achievementLegendaryBestiaryModalText": "You collected all the mythical pets!" } diff --git a/website/common/script/content/achievements.js b/website/common/script/content/achievements.js index 6ccb065990..4b8d1ccd2d 100644 --- a/website/common/script/content/achievements.js +++ b/website/common/script/content/achievements.js @@ -232,6 +232,11 @@ const basicAchievs = { titleKey: 'achievementRedLetterDay', textKey: 'achievementRedLetterDayText', }, + legendaryBestiary: { + icon: 'achievement-legendaryBestiary', + titleKey: 'achievementLegendaryBestiary', + textKey: 'achievementLegendaryBestiaryText', + }, }; Object.assign(achievementsData, basicAchievs); diff --git a/website/common/script/content/bundles.js b/website/common/script/content/bundles.js index cc68f86418..ceaa0cc395 100644 --- a/website/common/script/content/bundles.js +++ b/website/common/script/content/bundles.js @@ -190,7 +190,7 @@ const bundles = { 'gryphon', ], canBuy () { - return moment().isBetween('2019-02-19', '2019-03-02'); + return moment().isBefore('2021-02-28T08:00-05:00'); }, type: 'quests', value: 7, diff --git a/website/common/script/content/constants/animalSetAchievements.js b/website/common/script/content/constants/animalSetAchievements.js new file mode 100644 index 0000000000..04b56559f9 --- /dev/null +++ b/website/common/script/content/constants/animalSetAchievements.js @@ -0,0 +1,16 @@ +const ANIMAL_SET_ACHIEVEMENTS = { + legendaryBestiary: { + type: 'pet', + species: [ + 'Dragon', + 'FlyingPig', + 'Gryphon', + 'SeaSerpent', + 'Unicorn', + ], + achievementKey: 'legendaryBestiary', + notificationType: 'ACHIEVEMENT_LEGENDARY_BESTIARY', + }, +}; + +export default ANIMAL_SET_ACHIEVEMENTS; diff --git a/website/common/script/content/constants/index.js b/website/common/script/content/constants/index.js index 087105a958..3db080382a 100644 --- a/website/common/script/content/constants/index.js +++ b/website/common/script/content/constants/index.js @@ -30,5 +30,6 @@ export const USER_CAN_OWN_QUEST_CATEGORIES = [ export { EVENTS } from './events'; export { default as SEASONAL_SETS } from './seasonalSets'; export { default as ANIMAL_COLOR_ACHIEVEMENTS } from './animalColorAchievements'; +export { default as ANIMAL_SET_ACHIEVEMENTS } from './animalSetAchievements'; export { default as QUEST_SERIES_ACHIEVEMENTS } from './questSeriesAchievements'; export { default as ITEM_LIST } from './itemList'; diff --git a/website/common/script/content/index.js b/website/common/script/content/index.js index acf9abc128..ebc6937a55 100644 --- a/website/common/script/content/index.js +++ b/website/common/script/content/index.js @@ -11,6 +11,7 @@ import { ITEM_LIST, QUEST_SERIES_ACHIEVEMENTS, ANIMAL_COLOR_ACHIEVEMENTS, + ANIMAL_SET_ACHIEVEMENTS, } from './constants'; import achievements from './achievements'; @@ -43,6 +44,7 @@ const api = {}; api.achievements = achievements; api.questSeriesAchievements = QUEST_SERIES_ACHIEVEMENTS; api.animalColorAchievements = ANIMAL_COLOR_ACHIEVEMENTS; +api.animalSetAchievements = ANIMAL_SET_ACHIEVEMENTS; api.quests = quests; api.questsByLevel = questsByLevel; diff --git a/website/common/script/libs/achievements.js b/website/common/script/libs/achievements.js index bb4872d05d..be23cfdf08 100644 --- a/website/common/script/libs/achievements.js +++ b/website/common/script/libs/achievements.js @@ -208,6 +208,7 @@ function _getBasicAchievements (user, language) { _addSimple(result, user, { path: 'skeletonCrew', language }); _addSimple(result, user, { path: 'seeingRed', language }); _addSimple(result, user, { path: 'redLetterDay', language }); + _addSimple(result, user, { path: 'legendaryBestiary', language }); _addSimpleWithMasterCount(result, user, { path: 'beastMaster', language }); _addSimpleWithMasterCount(result, user, { path: 'mountMaster', language }); diff --git a/website/common/script/ops/hatch.js b/website/common/script/ops/hatch.js index 127aca0103..542312729c 100644 --- a/website/common/script/ops/hatch.js +++ b/website/common/script/ops/hatch.js @@ -59,25 +59,57 @@ export default function hatch (user, req = {}, analytics) { checkOnboardingStatus(user, req, analytics); } - forEach(content.animalColorAchievements, achievement => { - if (!user.achievements[achievement.petAchievement]) { - const petIndex = findIndex( - keys(content.dropEggs), - animal => !user.items.pets[`${animal}-${achievement.color}`] || user.items.pets[`${animal}-${achievement.color}`] <= 0, - ); - if (petIndex === -1) { - user.achievements[achievement.petAchievement] = true; - if (user.addNotification) { - const achievementString = `achievement${upperFirst(achievement.petAchievement)}`; - user.addNotification(achievement.petNotificationType, { - achievement: achievement.petAchievement, - message: `${i18n.t('modalAchievement')} ${i18n.t(achievementString)}`, - modalText: i18n.t(`${achievementString}ModalText`), - }); + if (content.dropEggs[egg]) { + forEach(content.animalColorAchievements, achievement => { + if (hatchingPotion !== achievement.color) return; + if (!user.achievements[achievement.petAchievement]) { + const petIndex = findIndex( + keys(content.dropEggs), + animal => !user.items.pets[`${animal}-${achievement.color}`] || user.items.pets[`${animal}-${achievement.color}`] <= 0, + ); + if (petIndex === -1) { + user.achievements[achievement.petAchievement] = true; + if (user.addNotification) { + const achievementString = `achievement${upperFirst(achievement.petAchievement)}`; + user.addNotification(achievement.petNotificationType, { + achievement: achievement.petAchievement, + message: `${i18n.t('modalAchievement')} ${i18n.t(achievementString)}`, + modalText: i18n.t(`${achievementString}ModalText`), + }); + } } } - } - }); + }); + } + + if (content.dropHatchingPotions[hatchingPotion]) { + forEach(content.animalSetAchievements, achievement => { + if (!user.achievements[achievement.achievementKey]) { + if (achievement.type === 'pet') { + let achieved = true; + forEach(achievement.species, species => { + if (!achieved) return; + const petIndex = findIndex( + keys(content.dropHatchingPotions), + color => !user.items.pets[`${species}-${color}`], + ); + if (petIndex !== -1) achieved = false; + }); + if (achieved) { + user.achievements[achievement.achievementKey] = true; + if (user.addNotification) { + const achievementString = `achievement${upperFirst(achievement.achievementKey)}`; + user.addNotification(achievement.notificationType, { + achievement: achievement.achievementKey, + message: `${i18n.t('modalAchievement')} ${i18n.t(achievementString)}`, + modalText: i18n.t(`${achievementString}ModalText`), + }); + } + } + } + } + }); + } if (analytics && moment().diff(user.auth.timestamps.created, 'days') < 7) { analytics.track('pet hatch', { diff --git a/website/raw_sprites/spritesmith/achievements/achievement-legendaryBestiary2x.png b/website/raw_sprites/spritesmith/achievements/achievement-legendaryBestiary2x.png new file mode 100644 index 0000000000..2f195921ab Binary files /dev/null and b/website/raw_sprites/spritesmith/achievements/achievement-legendaryBestiary2x.png differ diff --git a/website/server/models/user/schema.js b/website/server/models/user/schema.js index cee70b3105..6cae485112 100644 --- a/website/server/models/user/schema.js +++ b/website/server/models/user/schema.js @@ -140,6 +140,7 @@ export default new Schema({ skeletonCrew: Boolean, seeingRed: Boolean, redLetterDay: Boolean, + legendaryBestiary: Boolean, // Onboarding Guide createdTask: Boolean, completedTask: Boolean, diff --git a/website/server/models/userNotification.js b/website/server/models/userNotification.js index 86f4520834..1d71dd01bd 100644 --- a/website/server/models/userNotification.js +++ b/website/server/models/userNotification.js @@ -63,6 +63,7 @@ const NOTIFICATION_TYPES = [ 'ACHIEVEMENT_SKELETON_CREW', 'ACHIEVEMENT_SEEING_RED', 'ACHIEVEMENT_RED_LETTER_DAY', + 'ACHIEVEMENT_LEGENDARY_BESTIARY', 'ACHIEVEMENT', // generic achievement notification, details inside `notification.data` 'DROP_CAP_REACHED', ];