diff --git a/migrations/archive/2019/20191210_pet_color_achievements.js b/migrations/archive/2019/20191210_pet_color_achievements.js new file mode 100644 index 0000000000..6f0c4a4f99 --- /dev/null +++ b/migrations/archive/2019/20191210_pet_color_achievements.js @@ -0,0 +1,82 @@ +/* eslint-disable no-console */ +const MIGRATION_NAME = '20191210_pet_color_achievements'; +import { model as User } from '../../../website/server/models/user'; + +const progressCount = 1000; +let count = 0; + +async function updateUser (user) { + count++; + + let set = { + migration: MIGRATION_NAME, + }; + + if (user && user.items && user.items.pets) { + const pets = user.items.pets; + if (pets['Wolf-White'] > 0 + && pets['TigerCub-White'] > 0 + && pets['PandaCub-White'] > 0 + && pets['LionCub-White'] > 0 + && pets['Fox-White'] > 0 + && pets['FlyingPig-White'] > 0 + && pets['Dragon-White'] > 0 + && pets['Cactus-White'] > 0 + && pets['BearCub-White'] > 0) { + set['achievements.primedForPainting'] = true; + } + } + + if (user && user.items && user.items.mounts) { + const mounts = user.items.mounts; + if (mounts['Wolf-White'] + && mounts['TigerCub-White'] + && mounts['PandaCub-White'] + && mounts['LionCub-White'] + && mounts['Fox-White'] + && mounts['FlyingPig-White'] + && mounts['Dragon-White'] + && mounts['Cactus-White'] + && mounts['BearCub-White'] ) { + set['achievements.pearlyPro'] = 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('2019-12-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 2b0aeaa835..e4dc02dc5e 100644 --- a/website/client/src/components/notifications.vue +++ b/website/client/src/components/notifications.vue @@ -235,6 +235,16 @@ const NOTIFICATIONS = { label: $t => `${$t('achievement')}: ${$t('achievementUndeadUndertaker')}`, modalId: 'generic-achievement', }, + ACHIEVEMENT_PRIMED_FOR_PAINTING: { + achievement: true, + label: $t => `${$t('achievement')}: ${$t('achievementPrimedForPainting')}`, + modalId: 'generic-achievement', + }, + ACHIEVEMENT_PEARLY_PRO: { + achievement: true, + label: $t => `${$t('achievement')}: ${$t('achievementPearlyPro')}`, + modalId: 'generic-achievement', + }, }; export default { @@ -291,7 +301,8 @@ export default { 'CRON', 'SCORED_TASK', 'LOGIN_INCENTIVE', 'ACHIEVEMENT_ALL_YOUR_BASE', 'ACHIEVEMENT_BACK_TO_BASICS', 'GENERIC_ACHIEVEMENT', 'ACHIEVEMENT_PARTY_UP', 'ACHIEVEMENT_PARTY_ON', 'ACHIEVEMENT_BEAST_MASTER', 'ACHIEVEMENT_MOUNT_MASTER', 'ACHIEVEMENT_TRIAD_BINGO', 'ACHIEVEMENT_DUST_DEVIL', 'ACHIEVEMENT_ARID_AUTHORITY', - 'ACHIEVEMENT_MONSTER_MAGUS', 'ACHIEVEMENT_UNDEAD_UNDERTAKER', 'GENERIC_ACHIEVEMENT', + 'ACHIEVEMENT_MONSTER_MAGUS', 'ACHIEVEMENT_UNDEAD_UNDERTAKER', 'ACHIEVEMENT_PRIMED_FOR_PAINTING', + 'ACHIEVEMENT_PEARLY_PRO', 'GENERIC_ACHIEVEMENT', ].forEach(type => { handledNotifications[type] = true; }); @@ -697,6 +708,8 @@ export default { case 'ACHIEVEMENT_TRIAD_BINGO': case 'ACHIEVEMENT_MONSTER_MAGUS': case 'ACHIEVEMENT_UNDEAD_UNDERTAKER': + case 'ACHIEVEMENT_PRIMED_FOR_PAINTING': + case 'ACHIEVEMENT_PEARLY_PRO': case 'GENERIC_ACHIEVEMENT': this.showNotificationWithModal(notification); break; diff --git a/website/common/locales/en/achievements.json b/website/common/locales/en/achievements.json index 357e0f7ff3..cbf424e89d 100644 --- a/website/common/locales/en/achievements.json +++ b/website/common/locales/en/achievements.json @@ -34,5 +34,11 @@ "achievementMonsterMagusModalText": "You collected all the Zombie Pets!", "achievementUndeadUndertaker": "Undead Undertaker", "achievementUndeadUndertakerText": "Has tamed all Zombie Mounts.", - "achievementUndeadUndertakerModalText": "You tamed all the Zombie Mounts!" + "achievementUndeadUndertakerModalText": "You tamed all the Zombie Mounts!", + "achievementPrimedForPainting": "Primed for Painting", + "achievementPrimedForPaintingText": "Has collected all White Pets.", + "achievementPrimedForPaintingModalText": "You collected all the White Pets!", + "achievementPearlyPro": "Pearly Pro", + "achievementPearlyProText": "Has tamed all White Mounts.", + "achievementPearlyProModalText": "You tamed all the White Mounts!" } diff --git a/website/common/script/content/achievements.js b/website/common/script/content/achievements.js index 011dcc40c8..6b13df74d9 100644 --- a/website/common/script/content/achievements.js +++ b/website/common/script/content/achievements.js @@ -167,6 +167,16 @@ const basicAchievs = { titleKey: 'achievementUndeadUndertaker', textKey: 'achievementUndeadUndertakerText', }, + primedForPainting: { + icon: 'achievement-primedForPainting', + titleKey: 'achievementPrimedForPainting', + textKey: 'achievementPrimedForPaintingText', + }, + pearlyPro: { + icon: 'achievement-pearlyPro', + titleKey: 'achievementPearlyPro', + textKey: 'achievementPearlyProText', + }, }; Object.assign(achievementsData, basicAchievs); diff --git a/website/common/script/content/constants.js b/website/common/script/content/constants.js index 1b210c5749..39e25f54e0 100644 --- a/website/common/script/content/constants.js +++ b/website/common/script/content/constants.js @@ -273,4 +273,7 @@ export const ANIMAL_COLOR_ACHIEVEMENTS = [ { color: 'Zombie', petAchievement: 'monsterMagus', petNotificationType: 'ACHIEVEMENT_MONSTER_MAGUS', mountAchievement: 'undeadUndertaker', mountNotificationType: 'ACHIEVEMENT_UNDEAD_UNDERTAKER', }, + { + color: 'White', petAchievement: 'primedForPainting', petNotificationType: 'ACHIEVEMENT_PRIMED_FOR_PAINTING', mountAchievement: 'pearlyPro', mountNotificationType: 'ACHIEVEMENT_PEARLY_PRO', + }, ]; diff --git a/website/common/script/libs/achievements.js b/website/common/script/libs/achievements.js index c1e6048d3e..9bfdab6eec 100644 --- a/website/common/script/libs/achievements.js +++ b/website/common/script/libs/achievements.js @@ -195,6 +195,8 @@ function _getBasicAchievements (user, language) { _addSimple(result, user, { path: 'aridAuthority', language }); _addSimple(result, user, { path: 'monsterMagus', language }); _addSimple(result, user, { path: 'undeadUndertaker', language }); + _addSimple(result, user, { path: 'primedForPainting', language }); + _addSimple(result, user, { path: 'pearlyPro', language }); _addSimpleWithMasterCount(result, user, { path: 'beastMaster', language }); _addSimpleWithMasterCount(result, user, { path: 'mountMaster', language }); diff --git a/website/raw_sprites/spritesmith/achievements/achievement-aridAuthority2x.png b/website/raw_sprites/spritesmith/achievements/achievement-aridAuthority2x.png index 3e721fff8c..5dcdfb6b92 100644 Binary files a/website/raw_sprites/spritesmith/achievements/achievement-aridAuthority2x.png and b/website/raw_sprites/spritesmith/achievements/achievement-aridAuthority2x.png differ diff --git a/website/raw_sprites/spritesmith/achievements/achievement-dustDevil2x.png b/website/raw_sprites/spritesmith/achievements/achievement-dustDevil2x.png index 4917092baf..f1966e216b 100644 Binary files a/website/raw_sprites/spritesmith/achievements/achievement-dustDevil2x.png and b/website/raw_sprites/spritesmith/achievements/achievement-dustDevil2x.png differ diff --git a/website/raw_sprites/spritesmith/achievements/achievement-pearlyPro2x.png b/website/raw_sprites/spritesmith/achievements/achievement-pearlyPro2x.png new file mode 100644 index 0000000000..153520a2de Binary files /dev/null and b/website/raw_sprites/spritesmith/achievements/achievement-pearlyPro2x.png differ diff --git a/website/raw_sprites/spritesmith/achievements/achievement-primedForPainting2x.png b/website/raw_sprites/spritesmith/achievements/achievement-primedForPainting2x.png new file mode 100644 index 0000000000..331f62961e Binary files /dev/null and b/website/raw_sprites/spritesmith/achievements/achievement-primedForPainting2x.png differ diff --git a/website/raw_sprites/spritesmith_large/promo_achievement_white.png b/website/raw_sprites/spritesmith_large/promo_achievement_white.png new file mode 100644 index 0000000000..ef52821552 Binary files /dev/null and b/website/raw_sprites/spritesmith_large/promo_achievement_white.png differ diff --git a/website/server/controllers/api-v3/news.js b/website/server/controllers/api-v3/news.js index c37307cdaa..d2ac2b39e2 100644 --- a/website/server/controllers/api-v3/news.js +++ b/website/server/controllers/api-v3/news.js @@ -4,7 +4,7 @@ const 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!'; +const LAST_ANNOUNCEMENT_TITLE = 'NEW PET COLLECTION BADGES!'; const worldDmg = { // @TODO bailey: false, }; @@ -31,23 +31,22 @@ api.getNews = {
- We’ve added three new backgrounds to the Background Shop! Now your avatar can shop a - cheerful Holiday Market, enjoy the scent of a Holiday Wreath and bask in the starlight - of a Winter Nocturne. Check them out under User Icon > Backgrounds! + We're releasing a new achievement so you can celebrate your successes in the world of + Habitican pet collecting! Earn the Primed for Painting and Pearly Pro achievements by + collecting White pets and mounts and you'll earn a nifty badge for your profile.
- Plus, there’s new Gold-purchasable equipment in the Enchanted Armoire, including the - Duffle Coat and Ear-Flap Hat. Better work hard on your real-life tasks to earn all - the pieces! Enjoy :) + If you already have all the White pets and/or mounts in your stable, you'll receive the + badge automatically! Check your profile and celebrate your new achievement with pride.