feat(content): Habitica Birthday 2019

This commit is contained in:
Sabe Jones
2019-01-31 17:10:56 -06:00
parent 4e8c08ba9b
commit b1f42dcac9
15 changed files with 129 additions and 14 deletions

View File

@@ -0,0 +1,88 @@
/* eslint-disable no-console */
const MIGRATION_NAME = '20190131_habit_birthday';
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 inc = {
'items.food.Cake_Skeleton': 1,
'items.food.Cake_Base': 1,
'items.food.Cake_CottonCandyBlue': 1,
'items.food.Cake_CottonCandyPink': 1,
'items.food.Cake_Shade': 1,
'items.food.Cake_White': 1,
'items.food.Cake_Golden': 1,
'items.food.Cake_Zombie': 1,
'items.food.Cake_Desert': 1,
'items.food.Cake_Red': 1,
'achievements.habitBirthdays': 1,
};
const set = {};
let push;
set.migration = MIGRATION_NAME;
if (typeof user.items.gear.owned.armor_special_birthday2018 !== 'undefined') {
set['items.gear.owned.armor_special_birthday2019'] = false;
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.armor_special_birthday2019', _id: uuid()}};
} else if (typeof user.items.gear.owned.armor_special_birthday2017 !== 'undefined') {
set['items.gear.owned.armor_special_birthday2018'] = false;
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.armor_special_birthday2018', _id: uuid()}};
} else if (typeof user.items.gear.owned.armor_special_birthday2016 !== 'undefined') {
set['items.gear.owned.armor_special_birthday2017'] = false;
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.armor_special_birthday2017', _id: uuid()}};
} else if (typeof user.items.gear.owned.armor_special_birthday2015 !== 'undefined') {
set['items.gear.owned.armor_special_birthday2016'] = false;
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.armor_special_birthday2016', _id: uuid()}};
} else if (typeof user.items.gear.owned.armor_special_birthday !== 'undefined') {
set['items.gear.owned.armor_special_birthday2015'] = false;
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.armor_special_birthday2015', _id: uuid()}};
} else {
set['items.gear.owned.armor_special_birthday'] = false;
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.armor_special_birthday', _id: uuid()}};
}
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
return await User.update({_id: user._id}, {$inc: inc, $set: set, $push: push}).exec();
}
module.exports = async function processUsers () {
let query = {
migration: {$ne: MIGRATION_NAME},
'auth.timestamps.loggedin': {$gt: new Date('2019-01-15')},
};
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
}
};

View File

@@ -13,7 +13,7 @@ import forEach from 'lodash/forEach';
import moment from 'moment'; import moment from 'moment';
describe('shared.ops.purchase', () => { describe('shared.ops.purchase', () => {
const SEASONAL_FOOD = 'Meat'; const SEASONAL_FOOD = 'Cake_Base';
let user; let user;
let goldPoints = 40; let goldPoints = 40;
let analytics = {track () {}}; let analytics = {track () {}};

View File

@@ -2,8 +2,8 @@
// possible values are: normal, fall, habitoween, thanksgiving, winter, nye, birthday, valentines, spring, summer // possible values are: normal, fall, habitoween, thanksgiving, winter, nye, birthday, valentines, spring, summer
// more to be added on future seasons // more to be added on future seasons
$npc_market_flavor: 'winter'; $npc_market_flavor: 'birthday';
$npc_quests_flavor: 'winter'; $npc_quests_flavor: 'birthday';
$npc_seasonal_flavor: 'winter'; $npc_seasonal_flavor: 'birthday';
$npc_timetravelers_flavor: 'winter'; $npc_timetravelers_flavor: 'birthday';
$npc_tavern_flavor: 'winter'; $npc_tavern_flavor: 'birthday';

View File

@@ -511,6 +511,8 @@
"armorSpecialBirthday2017Notes": "Happy Birthday, Habitica! Wear these Whimsical Party Robes to celebrate this wonderful day. Confers no benefit.", "armorSpecialBirthday2017Notes": "Happy Birthday, Habitica! Wear these Whimsical Party Robes to celebrate this wonderful day. Confers no benefit.",
"armorSpecialBirthday2018Text": "Fanciful Party Robes", "armorSpecialBirthday2018Text": "Fanciful Party Robes",
"armorSpecialBirthday2018Notes": "Happy Birthday, Habitica! Wear these Fanciful Party Robes to celebrate this wonderful day. Confers no benefit.", "armorSpecialBirthday2018Notes": "Happy Birthday, Habitica! Wear these Fanciful Party Robes to celebrate this wonderful day. Confers no benefit.",
"armorSpecialBirthday2019Text": "Outlandish Party Robes",
"armorSpecialBirthday2019Notes": "Happy Birthday, Habitica! Wear these Outlandish Party Robes to celebrate this wonderful day. Confers no benefit.",
"armorSpecialGaymerxText": "Rainbow Warrior Armor", "armorSpecialGaymerxText": "Rainbow Warrior Armor",
"armorSpecialGaymerxNotes": "In celebration of the GaymerX Conference, this special armor is decorated with a radiant, colorful rainbow pattern! GaymerX is a game convention celebrating LGTBQ and gaming and is open to everyone.", "armorSpecialGaymerxNotes": "In celebration of the GaymerX Conference, this special armor is decorated with a radiant, colorful rainbow pattern! GaymerX is a game convention celebrating LGTBQ and gaming and is open to everyone.",

View File

@@ -1107,6 +1107,12 @@ let armor = {
value: 90, value: 90,
con: 15, con: 15,
}, },
birthday2019: {
text: t('armorSpecialBirthday2019Text'),
notes: t('armorSpecialBirthday2019Notes'),
value: 0,
canOwn: ownsItem('armor_special_birthday2019'),
},
}; };
let back = { let back = {

View File

@@ -356,12 +356,12 @@ api.specialMounts = stable.specialMounts;
api.mountInfo = stable.mountInfo; api.mountInfo = stable.mountInfo;
// For seasonal events, change these booleans: // For seasonal events, change these booleans:
let canBuyNormalFood = true; let canBuyNormalFood = false;
let canDropNormalFood = true; let canDropNormalFood = false;
let canBuyCandyFood = false; let canBuyCandyFood = false;
let canDropCandyFood = false; let canDropCandyFood = false;
let canBuyCakeFood = false; let canBuyCakeFood = true;
let canDropCakeFood = false; let canDropCakeFood = true;
api.food = { api.food = {
Meat: { Meat: {

Binary file not shown.

After

Width:  |  Height:  |  Size: 758 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 696 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 706 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -3,7 +3,7 @@ import { authWithHeaders } from '../../middlewares/auth';
let api = {}; let api = {};
// @TODO export this const, cannot export it from here because only routes are exported from controllers // @TODO export this const, cannot export it from here because only routes are exported from controllers
const LAST_ANNOUNCEMENT_TITLE = 'JANUARY SUBSCRIBER ITEMS REVEALED!'; const LAST_ANNOUNCEMENT_TITLE = 'HABITICA BIRTHDAY PARTY!';
const worldDmg = { // @TODO const worldDmg = { // @TODO
bailey: false, bailey: false,
}; };
@@ -30,14 +30,29 @@ api.getNews = {
<div class="mr-3 ${baileyClass}"></div> <div class="mr-3 ${baileyClass}"></div>
<div class="media-body"> <div class="media-body">
<h1 class="align-self-center">${res.t('newStuff')}</h1> <h1 class="align-self-center">${res.t('newStuff')}</h1>
<h2>1/28/2019 - ${LAST_ANNOUNCEMENT_TITLE}</h2> <h2>1/31/2019 - ${LAST_ANNOUNCEMENT_TITLE}</h2>
</div> </div>
</div> </div>
<hr/> <hr/>
<div class="promo_birthday_2019 center-block"></div>
<h3>Habitica Birthday Bash!</h3>
<p>January 31st is Habitica's Birthday! Thank you so much for being a part of our community - it means a lot.</p>
<p>Now come join us and the NPCs as we celebrate!</p>
<h3>Cake for Everybody!</h3>
<p>In honor of the festivities, everyone has been awarded an assortment of yummy cake to feed to your pets! Plus, for the next two days <a href='/shops/market'>Alexander the Merchant</a> is selling cake in his shop, and cake will sometimes drop when you complete your tasks. Cake works just like normal pet food, but if you want to know what type of pet likes each slice, <a href='http://habitica.wikia.com/wiki/Food' target='_blank'>the wiki has spoilers</a>.</p>
<h3>Party Robes</h3>
<p>There are Party Robes available for free in the Rewards column! What color you receive is based on how many Habitica Birthdays you've celebrated. Don them with pride!</p>
<h3>Birthday Bash Achievement</h3>
<p>In honor of Habitica's birthday, everyone has been awarded the Habitica Birthday Bash achievement! This achievement stacks for each Birthday Bash you celebrate with us.</p>
<div class="promo_mystery_201901 center-block"></div> <div class="promo_mystery_201901 center-block"></div>
<p>The January Subscriber Items have been revealed: the Polaris Item Set! You only have until Jan 31 to receive the item set when you <a href='/user/settings/subscription'>subscribe</a>. If you're already an active subscriber, reload the site and then head to Inventory > Items to claim your gear!</p> <h3>Last Chance for Polaris Set</h3>
<p>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.</p> <p>Reminder: tomorrow is the final day to <a href='/user/settings/subscription'>subscribe</a> and receive the Polaris Armor Set! Subscribing also lets you buy Gems for Gold. The longer your subscription, the more Gems you get!</p>
<p>Thanks so much for your support! You help keep Habitica running.</p>
<div class="small mb-3">by Beffymaroo</div> <div class="small mb-3">by Beffymaroo</div>
<div class="promo_snow_potions center-block"></div>
<h3>Last Chance for Winter Wonderland Hatching Potions</h3>
<p>Reminder: tomorrow is the final day to <a href='/shops/market'>buy Starry Night, Peppermint, and Icy Snow Hatching Potions</a>! If they come back, it won't be until next year at the earliest, so don't delay!</p>
<div class="small mb-3">by JinjooHat, Vampitch, Lemoness, and SabreCat</div>
</div> </div>
`, `,
}); });

View File

@@ -127,6 +127,10 @@ function _setUpNewUser (user) {
user.items.quests.dustbunnies = 1; user.items.quests.dustbunnies = 1;
user.purchased.background.violet = true; user.purchased.background.violet = true;
user.preferences.background = 'violet'; user.preferences.background = 'violet';
user.items.gear.owned.armor_special_birthday = true; // eslint-disable-line camelcase
user.items.gear.equipped.armor = 'armor_special_birthday';
user.items.gear.costume.armor = 'armor_special_birthday';
user.migration = '20190131_habit_birthday';
if (user.registeredThrough === 'habitica-web') { if (user.registeredThrough === 'habitica-web') {
taskTypes = ['habit', 'daily', 'todo', 'reward', 'tag']; taskTypes = ['habit', 'daily', 'todo', 'reward', 'tag'];