|
|
@ -16,7 +16,7 @@ const IMG_DIST_PATH = 'website/client/assets/images/sprites/';
|
|||
const CSS_DIST_PATH = 'website/client/assets/css/sprites/';
|
||||
|
||||
function checkForSpecialTreatment (name) {
|
||||
let regex = /^hair|skin|beard|mustach|shirt|flower|^headAccessory_special_\w+Ears|^eyewear_special_\w+TopFrame/;
|
||||
let regex = /^hair|skin|beard|mustach|shirt|flower|^headAccessory_special_\w+Ears|^eyewear_special_\w+TopFrame|^eyewear_special_\w+HalfMoon/;
|
||||
return name.match(regex) || name === 'head_0';
|
||||
}
|
||||
|
||||
|
|
|
|||
62
migrations/archive/2019/20190530_halfmoon_glasses.js
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/* eslint-disable no-console */
|
||||
const MIGRATION_NAME = '20190530_halfmoon_glasses';
|
||||
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 set = {
|
||||
'items.gear.owned.eyewear_special_blackHalfMoon': true,
|
||||
'items.gear.owned.eyewear_special_blueHalfMoon': true,
|
||||
'items.gear.owned.eyewear_special_greenHalfMoon': true,
|
||||
'items.gear.owned.eyewear_special_pinkHalfMoon': true,
|
||||
'items.gear.owned.eyewear_special_redHalfMoon': true,
|
||||
'items.gear.owned.eyewear_special_whiteHalfMoon': true,
|
||||
'items.gear.owned.eyewear_special_yellowHalfMoon': true,
|
||||
};
|
||||
|
||||
set.migration = MIGRATION_NAME;
|
||||
|
||||
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-05-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],
|
||||
};
|
||||
}
|
||||
|
||||
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
|
||||
}
|
||||
};
|
||||
|
|
@ -80,6 +80,13 @@ describe('shared.ops.buy', () => {
|
|||
headAccessory_special_redHeadband: true,
|
||||
headAccessory_special_whiteHeadband: true,
|
||||
headAccessory_special_yellowHeadband: true,
|
||||
eyewear_special_blackHalfMoon: true,
|
||||
eyewear_special_blueHalfMoon: true,
|
||||
eyewear_special_greenHalfMoon: true,
|
||||
eyewear_special_pinkHalfMoon: true,
|
||||
eyewear_special_redHalfMoon: true,
|
||||
eyewear_special_whiteHalfMoon: true,
|
||||
eyewear_special_yellowHalfMoon: true,
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -75,6 +75,13 @@ describe('shared.ops.buyMarketGear', () => {
|
|||
headAccessory_special_redHeadband: true,
|
||||
headAccessory_special_whiteHeadband: true,
|
||||
headAccessory_special_yellowHeadband: true,
|
||||
eyewear_special_blackHalfMoon: true,
|
||||
eyewear_special_blueHalfMoon: true,
|
||||
eyewear_special_greenHalfMoon: true,
|
||||
eyewear_special_pinkHalfMoon: true,
|
||||
eyewear_special_redHalfMoon: true,
|
||||
eyewear_special_whiteHalfMoon: true,
|
||||
eyewear_special_yellowHalfMoon: true,
|
||||
});
|
||||
expect(analytics.track).to.be.calledOnce;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ b-modal#avatar-modal(title="", :size='editing ? "lg" : "md"', :hide-header='true
|
|||
button.btn.btn-secondary.purchase-all(@click='unlock(`skin.${set.keys.join(",skin.")}`)') {{ $t('purchaseAll') }}
|
||||
#hair.section.customize-section(v-if='activeTopPage === "hair"')
|
||||
.row.col-12.sub-menu.text-center
|
||||
.col-3.text-center.sub-menu-item(@click='changeSubPage("color")', :class='{active: activeSubPage === "color"}')
|
||||
.col-3.text-center.sub-menu-item(@click='changeSubPage("color")', :class='{active: activeSubPage === "color", "offset-2": !editing}')
|
||||
strong(v-once) {{$t('color')}}
|
||||
.col-3.text-center.sub-menu-item(@click='changeSubPage("bangs")', :class='{active: activeSubPage === "bangs"}')
|
||||
strong(v-once) {{$t('bangs')}}
|
||||
|
|
@ -139,6 +139,7 @@ b-modal#avatar-modal(title="", :size='editing ? "lg" : "md"', :hide-header='true
|
|||
span 5
|
||||
button.btn.btn-secondary.purchase-all(@click='unlock(`hair.base.${baseHair4Keys.join(",hair.base.")}`)') {{ $t('purchaseAll') }}
|
||||
.col-12.customize-options
|
||||
.head_0.option(v-if="!editing", @click='set({"preferences.hair.base": 0})', :class="[{ active: user.preferences.hair.base === 0 }, 'hair_base_0_' + user.preferences.hair.color]")
|
||||
.option(v-for='option in baseHair1',
|
||||
:class='{active: user.preferences.hair.base === option}')
|
||||
.base.sprite.customize-option(:class="`hair_base_${option}_${user.preferences.hair.color}`", @click='set({"preferences.hair.base": option})')
|
||||
|
|
@ -1125,7 +1126,10 @@ export default {
|
|||
return options;
|
||||
},
|
||||
eyewear () {
|
||||
let keys = ['blackTopFrame', 'blueTopFrame', 'greenTopFrame', 'pinkTopFrame', 'redTopFrame', 'whiteTopFrame', 'yellowTopFrame'];
|
||||
let keys = [
|
||||
'blackTopFrame', 'blueTopFrame', 'greenTopFrame', 'pinkTopFrame', 'redTopFrame', 'whiteTopFrame', 'yellowTopFrame',
|
||||
'blackHalfMoon', 'blueHalfMoon', 'greenHalfMoon', 'pinkHalfMoon', 'redHalfMoon', 'whiteHalfMoon', 'yellowHalfMoon',
|
||||
];
|
||||
let options = keys.map(key => {
|
||||
let newKey = `eyewear_special_${key}`;
|
||||
let option = {};
|
||||
|
|
|
|||
|
|
@ -1938,6 +1938,21 @@
|
|||
"eyewearSpecialYellowTopFrameText": "Yellow Standard Eyeglasses",
|
||||
"eyewearSpecialYellowTopFrameNotes": "Glasses with a yellow frame above the lenses. Confers no benefit.",
|
||||
|
||||
"eyewearSpecialBlackHalfMoonText": "Black Half-Moon Eyeglasses",
|
||||
"eyewearSpecialBlackHalfMoonNotes": "Glasses with a black frame and crescent lenses. Confers no benefit.",
|
||||
"eyewearSpecialBlueHalfMoonText": "Blue Half-Moon Eyeglasses",
|
||||
"eyewearSpecialBlueHalfMoonNotes": "Glasses with a blue frame and crescent lenses. Confers no benefit.",
|
||||
"eyewearSpecialGreenHalfMoonText": "Green Half-Moon Eyeglasses",
|
||||
"eyewearSpecialGreenHalfMoonNotes": "Glasses with a green frame and crescent lenses. Confers no benefit.",
|
||||
"eyewearSpecialPinkHalfMoonText": "Pink Half-Moon Eyeglasses",
|
||||
"eyewearSpecialPinkHalfMoonNotes": "Glasses with a pink frame and crescent lenses. Confers no benefit.",
|
||||
"eyewearSpecialRedHalfMoonText": "Red Half-Moon Eyeglasses",
|
||||
"eyewearSpecialRedHalfMoonNotes": "Glasses with a red frame and crescent lenses. Confers no benefit.",
|
||||
"eyewearSpecialWhiteHalfMoonText": "White Half-Moon Eyeglasses",
|
||||
"eyewearSpecialWhiteHalfMoonNotes": "Glasses with a white frame and crescent lenses. Confers no benefit.",
|
||||
"eyewearSpecialYellowHalfMoonText": "Yellow Half-Moon Eyeglasses",
|
||||
"eyewearSpecialYellowHalfMoonNotes": "Glasses with a yellow frame and crescent lenses. Confers no benefit.",
|
||||
|
||||
"eyewearSpecialAetherMaskText": "Aether Mask",
|
||||
"eyewearSpecialAetherMaskNotes": "This mask has a mysterious history. Increases Intelligence by <%= int %>.",
|
||||
|
||||
|
|
|
|||
|
|
@ -1441,6 +1441,55 @@ let eyewear = {
|
|||
int: 10,
|
||||
canOwn: ownsItem('eyewear_special_aetherMask'),
|
||||
},
|
||||
blackHalfMoon: {
|
||||
gearSet: 'glasses',
|
||||
text: t('eyewearSpecialBlackHalfMoonText'),
|
||||
notes: t('eyewearSpecialBlackHalfMoonNotes'),
|
||||
value: 0,
|
||||
canOwn: ownsItem('eyewear_special_blackHalfMoon'),
|
||||
},
|
||||
blueHalfMoon: {
|
||||
gearSet: 'glasses',
|
||||
text: t('eyewearSpecialBlueHalfMoonText'),
|
||||
notes: t('eyewearSpecialBlueHalfMoonNotes'),
|
||||
value: 0,
|
||||
canOwn: ownsItem('eyewear_special_blueHalfMoon'),
|
||||
},
|
||||
greenHalfMoon: {
|
||||
gearSet: 'glasses',
|
||||
text: t('eyewearSpecialGreenHalfMoonText'),
|
||||
notes: t('eyewearSpecialGreenHalfMoonNotes'),
|
||||
value: 0,
|
||||
canOwn: ownsItem('eyewear_special_greenHalfMoon'),
|
||||
},
|
||||
pinkHalfMoon: {
|
||||
gearSet: 'glasses',
|
||||
text: t('eyewearSpecialPinkHalfMoonText'),
|
||||
notes: t('eyewearSpecialPinkHalfMoonNotes'),
|
||||
value: 0,
|
||||
canOwn: ownsItem('eyewear_special_pinkHalfMoon'),
|
||||
},
|
||||
redHalfMoon: {
|
||||
gearSet: 'glasses',
|
||||
text: t('eyewearSpecialRedHalfMoonText'),
|
||||
notes: t('eyewearSpecialRedHalfMoonNotes'),
|
||||
value: 0,
|
||||
canOwn: ownsItem('eyewear_special_redHalfMoon'),
|
||||
},
|
||||
whiteHalfMoon: {
|
||||
gearSet: 'glasses',
|
||||
text: t('eyewearSpecialWhiteHalfMoonText'),
|
||||
notes: t('eyewearSpecialWhiteHalfMoonNotes'),
|
||||
value: 0,
|
||||
canOwn: ownsItem('eyewear_special_whiteHalfMoon'),
|
||||
},
|
||||
yellowHalfMoon: {
|
||||
gearSet: 'glasses',
|
||||
text: t('eyewearSpecialYellowHalfMoonText'),
|
||||
notes: t('eyewearSpecialYellowHalfMoonNotes'),
|
||||
value: 0,
|
||||
canOwn: ownsItem('eyewear_special_yellowHalfMoon'),
|
||||
},
|
||||
};
|
||||
|
||||
let head = {
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 386 B |
|
After Width: | Height: | Size: 344 B |
|
After Width: | Height: | Size: 342 B |
|
After Width: | Height: | Size: 345 B |
|
After Width: | Height: | Size: 342 B |
|
After Width: | Height: | Size: 341 B |
|
After Width: | Height: | Size: 338 B |
|
After Width: | Height: | Size: 200 B |
|
Before Width: | Height: | Size: 355 B After Width: | Height: | Size: 226 B |
|
After Width: | Height: | Size: 210 B |
|
Before Width: | Height: | Size: 370 B After Width: | Height: | Size: 250 B |
|
After Width: | Height: | Size: 208 B |
|
Before Width: | Height: | Size: 370 B After Width: | Height: | Size: 249 B |
|
After Width: | Height: | Size: 213 B |
|
Before Width: | Height: | Size: 370 B After Width: | Height: | Size: 251 B |
|
After Width: | Height: | Size: 206 B |
|
Before Width: | Height: | Size: 370 B After Width: | Height: | Size: 239 B |
|
After Width: | Height: | Size: 203 B |
|
Before Width: | Height: | Size: 370 B After Width: | Height: | Size: 225 B |
|
After Width: | Height: | Size: 205 B |
|
Before Width: | Height: | Size: 370 B After Width: | Height: | Size: 233 B |
BIN
website/raw_sprites/spritesmith_large/promo_halfmoon_glasses.png
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 7.4 KiB |
|
|
@ -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 = 'MAY SUBSCRIBER ITEMS REVEALED!';
|
||||
const LAST_ANNOUNCEMENT_TITLE = 'NEW GLASSES OPTION FOR AVATARS AND LAST CHANCE FOR MAY LIMITED-TIME ITEMS';
|
||||
const worldDmg = { // @TODO
|
||||
bailey: false,
|
||||
};
|
||||
|
|
@ -30,14 +30,29 @@ api.getNews = {
|
|||
<div class="mr-3 ${baileyClass}"></div>
|
||||
<div class="media-body">
|
||||
<h1 class="align-self-center">${res.t('newStuff')}</h1>
|
||||
<h2>5/28/2019 - ${LAST_ANNOUNCEMENT_TITLE}</h2>
|
||||
<h2>5/30/2019 - ${LAST_ANNOUNCEMENT_TITLE}</h2>
|
||||
</div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="promo_halfmoon_glasses center-block"></div>
|
||||
<h3>New Glasses Option for Avatars</h3>
|
||||
<p>We have a new set of free avatar customizations available: half-moon glasses! We hope that all you glasses-wearing Habiticans out there will enjoy these new options. You can find them in User>Edit Avatar>Extras.</p>
|
||||
<div class="small mb-3">by Breadstrings and SabreCat</div>
|
||||
<div class="promo_mystery_201905 center-block"></div>
|
||||
<p>The May Subscriber Item has been revealed: the Dazzling Dragon Item Set! You only have until May 31 to receive the item set <a href='/user/settings/subscription'>when you subscribe</a>. If you're already an active subscriber, reload the site and then head to Inventory > Items to claim your gear!</p>
|
||||
<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>
|
||||
<div class="small mb-3">by beffymaroo</div>
|
||||
<h3>Last Chance for Dazzling Dragon Set</h3>
|
||||
<p>Reminder: tomorrow is the final day to <a href='/user/settings/subscription'>subscribe</a> and receive the Dazzling Dragon Set! Subscribing also lets you buy Gems with 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="promo_floral_sunshine_potions center-block"></div>
|
||||
<h3>Last Chance for Sunshine and Floral Hatching Potions</h3>
|
||||
<p>Reminder: tomorrow is the final day to <a href='/shops/market'>buy Sunshine and Floral 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 OuttaMyMind, Lt.Cabel, Eslyn, Mako, and SabreCat</div>
|
||||
<div class="promo_feathered_friends_bundle center-block"></div>
|
||||
<h3>Last Chance for Feathered Friends Quest Bundle</h3>
|
||||
<p>Tomorrow is also the final day to buy the discounted Feathered Friends Pet Quest Bundle, featuring the Falcon, Parrot, and Owl quests all for seven Gems! Be sure to get a few in your talons before they fly away! The bundle can be found in the <a href='/shops/quests'>Quest Shop</a>.</p>
|
||||
<div class="small">by Lemoness and SabreCat</div>
|
||||
<div class="small">Art by Casey, Teto Forever, Eevachu, UncommonCriminal, JonArinbjorn, Trogdorina, Onheiron, Squish</div>
|
||||
<div class="small mb-3">Writing by Lemoness, Token, and Bartelmy</div>
|
||||
</div>
|
||||
`,
|
||||
});
|
||||
|
|
|
|||