From c4f6644c3ac5ff1844edb450b62cc735907fb34a Mon Sep 17 00:00:00 2001 From: Sabe Jones Date: Tue, 24 Nov 2020 17:53:15 -0600 Subject: [PATCH] feat(content): Red Pet Achievement --- .../2020/20201124_pet_color_achievements.js | 82 ++++++++++++++++++ .../client/src/components/notifications.vue | 21 ++++- website/common/locales/en/achievements.json | 8 +- website/common/script/content/achievements.js | 10 +++ .../constants/animalColorAchievements.js | 7 ++ website/common/script/libs/achievements.js | 2 + .../achievement-redLetterDay2x.png | Bin 0 -> 4130 bytes .../achievements/achievement-seeingRed2x.png | Bin 0 -> 9690 bytes website/server/models/user/schema.js | 2 + website/server/models/userNotification.js | 2 + 10 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 migrations/archive/2020/20201124_pet_color_achievements.js create mode 100644 website/raw_sprites/spritesmith/achievements/achievement-redLetterDay2x.png create mode 100644 website/raw_sprites/spritesmith/achievements/achievement-seeingRed2x.png diff --git a/migrations/archive/2020/20201124_pet_color_achievements.js b/migrations/archive/2020/20201124_pet_color_achievements.js new file mode 100644 index 0000000000..c44d0dbd25 --- /dev/null +++ b/migrations/archive/2020/20201124_pet_color_achievements.js @@ -0,0 +1,82 @@ +/* eslint-disable no-console */ +const MIGRATION_NAME = '20201124_pet_color_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['Wolf-Red'] > 0 + && pets['TigerCub-Red'] > 0 + && pets['PandaCub-Red'] > 0 + && pets['LionCub-Red'] > 0 + && pets['Fox-Red'] > 0 + && pets['FlyingPig-Red'] > 0 + && pets['Dragon-Red'] > 0 + && pets['Cactus-Red'] > 0 + && pets['BearCub-Red'] > 0) { + set['achievements.seeingRed'] = true; + } + } + + if (user && user.items && user.items.mounts) { + const mounts = user.items.mounts; + if (mounts['Wolf-Red'] + && mounts['TigerCub-Red'] + && mounts['PandaCub-Red'] + && mounts['LionCub-Red'] + && mounts['Fox-Red'] + && mounts['FlyingPig-Red'] + && mounts['Dragon-Red'] + && mounts['Cactus-Red'] + && mounts['BearCub-Red'] ) { + set['achievements.redLetterDay'] = true; + } + } + + 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('2020-11-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/website/client/src/components/notifications.vue b/website/client/src/components/notifications.vue index f0ab25f004..d46030a9b5 100644 --- a/website/client/src/components/notifications.vue +++ b/website/client/src/components/notifications.vue @@ -370,6 +370,22 @@ const NOTIFICATIONS = { achievement: 'skeletonCrew', }, }, + ACHIEVEMENT_SEEING_RED: { + achievement: true, + label: $t => `${$t('achievement')}: ${$t('achievementSeeingRed')}`, + modalId: 'generic-achievement', + data: { + achievement: 'seeingRed', + }, + }, + ACHIEVEMENT_RED_LETTER_DAY: { + achievement: true, + label: $t => `${$t('achievement')}: ${$t('achievementRedLetterDay')}`, + modalId: 'generic-achievement', + data: { + achievement: 'redLetterDay', + }, + }, }; export default { @@ -431,7 +447,8 @@ export default { 'ACHIEVEMENT_PEARLY_PRO', 'ACHIEVEMENT_TICKLED_PINK', 'ACHIEVEMENT_ROSY_OUTLOOK', 'ACHIEVEMENT', '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_BONE_COLLECTOR', 'ACHIEVEMENT_SKELETON_CREW', 'ACHIEVEMENT_SEEING_RED', + 'ACHIEVEMENT_RED_LETTER_DAY', ].forEach(type => { handledNotifications[type] = true; }); @@ -850,6 +867,8 @@ export default { case 'ACHIEVEMENT_ALL_THAT_GLITTERS': case 'ACHIEVEMENT_BONE_COLLECTOR': case 'ACHIEVEMENT_SKELETON_CREW': + case 'ACHIEVEMENT_SEEING_RED': + case 'ACHIEVEMENT_RED_LETTER_DAY': case 'GENERIC_ACHIEVEMENT': this.showNotificationWithModal(notification); break; diff --git a/website/common/locales/en/achievements.json b/website/common/locales/en/achievements.json index de700eb78d..68079a5a14 100644 --- a/website/common/locales/en/achievements.json +++ b/website/common/locales/en/achievements.json @@ -96,5 +96,11 @@ "achievementBoneCollectorModalText": "You collected all the Skeleton Pets!", "achievementSkeletonCrew": "Skeleton Crew", "achievementSkeletonCrewText": "Has tamed all Skeleton Mounts.", - "achievementSkeletonCrewModalText": "You tamed all the Skeleton Mounts!" + "achievementSkeletonCrewModalText": "You tamed all the Skeleton Mounts!", + "achievementSeeingRed": "Seeing Red", + "achievementSeeingRedText": "Has collected all Red pets.", + "achievementSeeingRedModalText": "You collected all the Red Pets!", + "achievementRedLetterDay": "Red Letter Day", + "achievementRedLetterDayText": "Has tamed all Red Mounts.", + "achievementRedLetterDayModalText": "You tamed all the Red Mounts!" } diff --git a/website/common/script/content/achievements.js b/website/common/script/content/achievements.js index 4749f29486..6ccb065990 100644 --- a/website/common/script/content/achievements.js +++ b/website/common/script/content/achievements.js @@ -222,6 +222,16 @@ const basicAchievs = { titleKey: 'achievementSkeletonCrew', textKey: 'achievementSkeletonCrewText', }, + seeingRed: { + icon: 'achievement-seeingRed', + titleKey: 'achievementSeeingRed', + textKey: 'achievementSeeingRedText', + }, + redLetterDay: { + icon: 'achievement-redLetterDay', + titleKey: 'achievementRedLetterDay', + textKey: 'achievementRedLetterDayText', + }, }; Object.assign(achievementsData, basicAchievs); diff --git a/website/common/script/content/constants/animalColorAchievements.js b/website/common/script/content/constants/animalColorAchievements.js index 1be56ef0d6..df2918faae 100644 --- a/website/common/script/content/constants/animalColorAchievements.js +++ b/website/common/script/content/constants/animalColorAchievements.js @@ -48,6 +48,13 @@ const ANIMAL_COLOR_ACHIEVEMENTS = [ mountAchievement: 'skeletonCrew', mountNotificationType: 'ACHIEVEMENT_SKELETON_CREW', }, + { + color: 'Red', + petAchievement: 'seeingRed', + petNotificationType: 'ACHIEVEMENT_SEEING_RED', + mountAchievement: 'redLetterDay', + mountNotificationType: 'ACHIEVEMENT_RED_LETTER_DAY', + }, ]; export default ANIMAL_COLOR_ACHIEVEMENTS; diff --git a/website/common/script/libs/achievements.js b/website/common/script/libs/achievements.js index dac7e98ade..bb4872d05d 100644 --- a/website/common/script/libs/achievements.js +++ b/website/common/script/libs/achievements.js @@ -206,6 +206,8 @@ function _getBasicAchievements (user, language) { _addSimple(result, user, { path: 'allThatGlitters', language }); _addSimple(result, user, { path: 'boneCollector', language }); _addSimple(result, user, { path: 'skeletonCrew', language }); + _addSimple(result, user, { path: 'seeingRed', language }); + _addSimple(result, user, { path: 'redLetterDay', language }); _addSimpleWithMasterCount(result, user, { path: 'beastMaster', language }); _addSimpleWithMasterCount(result, user, { path: 'mountMaster', language }); diff --git a/website/raw_sprites/spritesmith/achievements/achievement-redLetterDay2x.png b/website/raw_sprites/spritesmith/achievements/achievement-redLetterDay2x.png new file mode 100644 index 0000000000000000000000000000000000000000..6a0efbbced4f950c463c6454f3bcb8d5347db06c GIT binary patch literal 4130 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 literal 0 HcmV?d00001 diff --git a/website/raw_sprites/spritesmith/achievements/achievement-seeingRed2x.png b/website/raw_sprites/spritesmith/achievements/achievement-seeingRed2x.png new file mode 100644 index 0000000000000000000000000000000000000000..771b6577b0ab905f603b42a5c7fb276860bcc73e GIT binary patch literal 9690 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 literal 0 HcmV?d00001 diff --git a/website/server/models/user/schema.js b/website/server/models/user/schema.js index c7f3c52952..cee70b3105 100644 --- a/website/server/models/user/schema.js +++ b/website/server/models/user/schema.js @@ -138,6 +138,8 @@ export default new Schema({ allThatGlitters: Boolean, boneCollector: Boolean, skeletonCrew: Boolean, + seeingRed: Boolean, + redLetterDay: Boolean, // Onboarding Guide createdTask: Boolean, completedTask: Boolean, diff --git a/website/server/models/userNotification.js b/website/server/models/userNotification.js index 7da9f98fef..86f4520834 100644 --- a/website/server/models/userNotification.js +++ b/website/server/models/userNotification.js @@ -61,6 +61,8 @@ const NOTIFICATION_TYPES = [ 'ACHIEVEMENT_ALL_THAT_GLITTERS', 'ACHIEVEMENT_BONE_COLLECTOR', 'ACHIEVEMENT_SKELETON_CREW', + 'ACHIEVEMENT_SEEING_RED', + 'ACHIEVEMENT_RED_LETTER_DAY', 'ACHIEVEMENT', // generic achievement notification, details inside `notification.data` 'DROP_CAP_REACHED', ];