Merge remote-tracking branch 'origin/develop' into negue/ui/setting
# Conflicts: # website/client/src/components/header/notificationsDropdown.vue
This commit is contained in:
@@ -535,6 +535,16 @@ const backgrounds = {
|
||||
inside_a_crystal: { },
|
||||
snowy_village: { },
|
||||
},
|
||||
backgrounds012023: {
|
||||
rime_ice: { },
|
||||
snowy_temple: { },
|
||||
winter_lake_with_swans: { },
|
||||
},
|
||||
eventBackgrounds: {
|
||||
birthday_bash: {
|
||||
price: 0,
|
||||
},
|
||||
},
|
||||
timeTravelBackgrounds: {
|
||||
airship: {
|
||||
price: 1,
|
||||
@@ -578,7 +588,9 @@ forOwn(backgrounds, (backgroundsInSet, set) => {
|
||||
forOwn(backgroundsInSet, (background, bgKey) => {
|
||||
background.key = bgKey;
|
||||
background.set = set;
|
||||
background.price = background.price || 7;
|
||||
if (background.price !== 0) {
|
||||
background.price = background.price || 7;
|
||||
}
|
||||
background.text = background.text || t(`background${upperFirst(camelCase(bgKey))}Text`);
|
||||
background.notes = background.notes || t(`background${upperFirst(camelCase(bgKey))}Notes`);
|
||||
|
||||
|
||||
@@ -10,11 +10,17 @@ const gemsPromo = {
|
||||
|
||||
export const EVENTS = {
|
||||
noEvent: {
|
||||
start: '2023-01-31T20:00-05:00',
|
||||
start: '2023-02-08T23:59-05:00',
|
||||
end: '2023-02-14T08:00-05:00',
|
||||
season: 'normal',
|
||||
npcImageSuffix: '',
|
||||
},
|
||||
birthday10: {
|
||||
start: '2023-01-30T08:00-05:00',
|
||||
end: '2023-02-08T23:59-05:00',
|
||||
season: 'birthday',
|
||||
npcImageSuffix: '_birthday',
|
||||
},
|
||||
winter2023: {
|
||||
start: '2022-12-20T08:00-05:00',
|
||||
end: '2023-01-31T23:59-05:00',
|
||||
|
||||
@@ -408,6 +408,9 @@ const armor = {
|
||||
int: 10,
|
||||
set: 'jewelers',
|
||||
},
|
||||
shawlCollarCoat: {
|
||||
con: 8,
|
||||
},
|
||||
};
|
||||
|
||||
const body = {
|
||||
|
||||
@@ -16,7 +16,8 @@ import t from '../../../translation';
|
||||
import { getClassName } from '../../../../libs/getClassName';
|
||||
|
||||
const CURRENT_EVENT = find(
|
||||
EVENTS, event => moment().isBetween(event.start, event.end) && Boolean(event.season),
|
||||
EVENTS, event => moment().isBetween(event.start, event.end)
|
||||
&& ['winter', 'spring', 'summer', 'fall'].includes(event.season),
|
||||
);
|
||||
|
||||
const gearEvents = pickBy(EVENTS, event => event.gear);
|
||||
@@ -798,6 +799,12 @@ const armor = {
|
||||
winter2023Healer: {
|
||||
set: 'winter2023CardinalHealerSet',
|
||||
},
|
||||
birthday2023: {
|
||||
text: t('armorSpecialBirthday2023Text'),
|
||||
notes: t('armorSpecialBirthday2023Notes'),
|
||||
value: 0,
|
||||
canOwn: ownsItem('armor_special_birthday2023'),
|
||||
},
|
||||
};
|
||||
|
||||
const armorStats = {
|
||||
@@ -923,6 +930,12 @@ const back = {
|
||||
value: 0,
|
||||
canOwn: ownsItem('back_special_namingDay2020'),
|
||||
},
|
||||
anniversary: {
|
||||
text: t('backSpecialAnniversaryText'),
|
||||
notes: t('backSpecialAnniversaryNotes'),
|
||||
value: 0,
|
||||
canOwn: ownsItem('back_special_anniversary'),
|
||||
},
|
||||
};
|
||||
|
||||
const body = {
|
||||
@@ -992,6 +1005,12 @@ const body = {
|
||||
value: 0,
|
||||
canOwn: ownsItem('body_special_namingDay2018'),
|
||||
},
|
||||
anniversary: {
|
||||
text: t('bodySpecialAnniversaryText'),
|
||||
notes: t('bodySpecialAnniversaryNotes'),
|
||||
value: 0,
|
||||
canOwn: ownsItem('body_special_anniversary'),
|
||||
},
|
||||
};
|
||||
|
||||
const eyewear = {
|
||||
@@ -1140,6 +1159,12 @@ const eyewear = {
|
||||
value: 0,
|
||||
canOwn: ownsItem('eyewear_special_ks2019'),
|
||||
},
|
||||
anniversary: {
|
||||
text: t('eyewearSpecialAnniversaryText'),
|
||||
notes: t('eyewearSpecialAnniversaryNotes'),
|
||||
value: 0,
|
||||
canOwn: ownsItem('eyewear_special_anniversary'),
|
||||
},
|
||||
};
|
||||
|
||||
const head = {
|
||||
|
||||
@@ -70,13 +70,13 @@ const premium = {
|
||||
value: 2,
|
||||
text: t('hatchingPotionShimmer'),
|
||||
limited: true,
|
||||
event: EVENTS.spring2022,
|
||||
event: EVENTS.birthday10,
|
||||
_addlNotes: t('eventAvailabilityReturning', {
|
||||
availableDate: t('dateEndMarch'),
|
||||
previousDate: t('marchYYYY', { year: 2020 }),
|
||||
availableDate: t('dateStartFebruary'),
|
||||
previousDate: t('marchYYYY', { year: 2022 }),
|
||||
}),
|
||||
canBuy () {
|
||||
return moment().isBefore(EVENTS.spring2022.end);
|
||||
return moment().isBetween(EVENTS.birthday10.start, EVENTS.birthday10.end);
|
||||
},
|
||||
},
|
||||
Fairy: {
|
||||
@@ -109,13 +109,13 @@ const premium = {
|
||||
value: 2,
|
||||
text: t('hatchingPotionAquatic'),
|
||||
limited: true,
|
||||
event: EVENTS.summer2022,
|
||||
event: EVENTS.birthday10,
|
||||
_addlNotes: t('eventAvailabilityReturning', {
|
||||
availableDate: t('dateEndJuly'),
|
||||
previousDate: t('augustYYYY', { year: 2020 }),
|
||||
availableDate: t('dateStartFebruary'),
|
||||
previousDate: t('julyYYYY', { year: 2022 }),
|
||||
}),
|
||||
canBuy () {
|
||||
return moment().isBetween(EVENTS.summer2022.start, EVENTS.summer2022.end);
|
||||
return moment().isBetween(EVENTS.birthday10.start, EVENTS.birthday10.end);
|
||||
},
|
||||
},
|
||||
Ember: {
|
||||
@@ -188,12 +188,12 @@ const premium = {
|
||||
text: t('hatchingPotionPeppermint'),
|
||||
limited: true,
|
||||
_addlNotes: t('eventAvailabilityReturning', {
|
||||
availableDate: t('dateEndJanuary'),
|
||||
previousDate: t('januaryYYYY', { year: 2018 }),
|
||||
availableDate: t('dateStartFebruary'),
|
||||
previousDate: t('januaryYYYY', { year: 2022 }),
|
||||
}),
|
||||
event: EVENTS.winter2022,
|
||||
event: EVENTS.birthday10,
|
||||
canBuy () {
|
||||
return moment().isBetween(EVENTS.winter2022.start, EVENTS.winter2022.end);
|
||||
return moment().isBetween(EVENTS.birthday10.start, EVENTS.birthday10.end);
|
||||
},
|
||||
},
|
||||
StarryNight: {
|
||||
@@ -239,13 +239,13 @@ const premium = {
|
||||
value: 2,
|
||||
text: t('hatchingPotionGlow'),
|
||||
limited: true,
|
||||
event: EVENTS.fall2021,
|
||||
event: EVENTS.birthday10,
|
||||
_addlNotes: t('eventAvailabilityReturning', {
|
||||
availableDate: t('dateEndOctober'),
|
||||
previousDate: t('septemberYYYY', { year: 2019 }),
|
||||
availableDate: t('dateStartFebruary'),
|
||||
previousDate: t('octoberYYYY', { year: 2021 }),
|
||||
}),
|
||||
canBuy () {
|
||||
return moment().isBefore(EVENTS.fall2021.end);
|
||||
return moment().isBetween(EVENTS.birthday10.start, EVENTS.birthday10.end);
|
||||
},
|
||||
},
|
||||
Frost: {
|
||||
@@ -286,13 +286,13 @@ const premium = {
|
||||
value: 2,
|
||||
text: t('hatchingPotionCelestial'),
|
||||
limited: true,
|
||||
event: EVENTS.spring2022,
|
||||
event: EVENTS.birthday10,
|
||||
_addlNotes: t('eventAvailabilityReturning', {
|
||||
availableDate: t('dateEndMarch'),
|
||||
previousDate: t('marchYYYY', { year: 2020 }),
|
||||
availableDate: t('dateStartFebruary'),
|
||||
previousDate: t('marchYYYY', { year: 2022 }),
|
||||
}),
|
||||
canBuy () {
|
||||
return moment().isBefore(EVENTS.spring2022.end);
|
||||
return moment().isBetween(EVENTS.birthday10.start, EVENTS.birthday10.end);
|
||||
},
|
||||
},
|
||||
Sunshine: {
|
||||
@@ -399,13 +399,13 @@ const premium = {
|
||||
value: 2,
|
||||
text: t('hatchingPotionSandSculpture'),
|
||||
limited: true,
|
||||
event: EVENTS.summer2021,
|
||||
event: EVENTS.birthday10,
|
||||
_addlNotes: t('eventAvailabilityReturning', {
|
||||
availableDate: t('dateEndJuly'),
|
||||
previousDate: t('juneYYYY', { year: 2020 }),
|
||||
availableDate: t('dateStartFebruary'),
|
||||
previousDate: t('julyYYYY', { year: 2021 }),
|
||||
}),
|
||||
canBuy () {
|
||||
return moment().isBetween(EVENTS.summer2021.start, EVENTS.summer2021.end);
|
||||
return moment().isBetween(EVENTS.birthday10.start, EVENTS.birthday10.end);
|
||||
},
|
||||
},
|
||||
Windup: {
|
||||
@@ -426,26 +426,26 @@ const premium = {
|
||||
value: 2,
|
||||
text: t('hatchingPotionVampire'),
|
||||
limited: true,
|
||||
event: EVENTS.fall2022,
|
||||
event: EVENTS.birthday10,
|
||||
_addlNotes: t('eventAvailabilityReturning', {
|
||||
availableDate: t('dateEndOctober'),
|
||||
previousDate: t('octoberYYYY', { year: 2021 }),
|
||||
availableDate: t('dateStartFebruary'),
|
||||
previousDate: t('octoberYYYY', { year: 2022 }),
|
||||
}),
|
||||
canBuy () {
|
||||
return moment().isBetween(EVENTS.fall2022.start, EVENTS.fall2022.end);
|
||||
return moment().isBetween(EVENTS.birthday10.start, EVENTS.birthday10.end);
|
||||
},
|
||||
},
|
||||
AutumnLeaf: {
|
||||
value: 2,
|
||||
text: t('hatchingPotionAutumnLeaf'),
|
||||
limited: true,
|
||||
event: EVENTS.potions202111,
|
||||
event: EVENTS.birthday10,
|
||||
_addlNotes: t('eventAvailabilityReturning', {
|
||||
availableDate: t('dateEndNovember'),
|
||||
previousDate: t('novemberYYYY', { year: 2020 }),
|
||||
availableDate: t('dateStartFebruary'),
|
||||
previousDate: t('novemberYYYY', { year: 2021 }),
|
||||
}),
|
||||
canBuy () {
|
||||
return moment().isBefore(EVENTS.potions202111.end);
|
||||
return moment().isBetween(EVENTS.birthday10.start, EVENTS.birthday10.end);
|
||||
},
|
||||
},
|
||||
BlackPearl: {
|
||||
@@ -460,12 +460,12 @@ const premium = {
|
||||
text: t('hatchingPotionStainedGlass'),
|
||||
limited: true,
|
||||
_addlNotes: t('eventAvailabilityReturning', {
|
||||
availableDate: t('dateEndJanuary'),
|
||||
previousDate: t('januaryYYYY', { year: 2021 }),
|
||||
availableDate: t('dateStartFebruary'),
|
||||
previousDate: t('januaryYYYY', { year: 2022 }),
|
||||
}),
|
||||
event: EVENTS.winter2022,
|
||||
event: EVENTS.birthday10,
|
||||
canBuy () {
|
||||
return moment().isBetween(EVENTS.winter2022.start, EVENTS.winter2022.end);
|
||||
return moment().isBetween(EVENTS.birthday10.start, EVENTS.birthday10.end);
|
||||
},
|
||||
},
|
||||
PolkaDot: {
|
||||
@@ -532,12 +532,13 @@ const premium = {
|
||||
value: 2,
|
||||
text: t('hatchingPotionPorcelain'),
|
||||
limited: true,
|
||||
event: EVENTS.potions202208,
|
||||
_addlNotes: t('premiumPotionAddlNotes', {
|
||||
date: t('dateEndAugust'),
|
||||
event: EVENTS.birthday10,
|
||||
_addlNotes: t('eventAvailabilityReturning', {
|
||||
availableDate: t('dateStartFebruary'),
|
||||
previousDate: t('augustYYYY', { year: 2022 }),
|
||||
}),
|
||||
canBuy () {
|
||||
return moment().isBetween(EVENTS.potions202208.start, EVENTS.potions202208.end);
|
||||
return moment().isBetween(EVENTS.birthday10.start, EVENTS.birthday10.end);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -127,7 +127,7 @@ api.cardTypes = {
|
||||
nye: {
|
||||
key: 'nye',
|
||||
messageOptions: 5,
|
||||
yearRound: moment().isBefore('2022-01-02T20:00-04:00'),
|
||||
yearRound: moment().isBefore('2023-01-02T20:00-05:00'),
|
||||
},
|
||||
thankyou: {
|
||||
key: 'thankyou',
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import each from 'lodash/each';
|
||||
import moment from 'moment';
|
||||
import { EVENTS } from './constants/events';
|
||||
import {
|
||||
drops as dropEggs,
|
||||
quests as questEggs,
|
||||
@@ -118,6 +120,9 @@ const canFindSpecial = {
|
||||
'Jackalope-RoyalPurple': true, // subscription
|
||||
'Wolf-Cerberus': false, // Pet once granted to backers
|
||||
'Gryphon-Gryphatrice': false, // Pet once granted to kickstarter
|
||||
|
||||
// Birthday Pet
|
||||
'Gryphatrice-Jubilant': false,
|
||||
},
|
||||
mounts: {
|
||||
// Thanksgiving pet ladder
|
||||
@@ -174,6 +179,7 @@ const specialPets = {
|
||||
'Fox-Veteran': 'veteranFox',
|
||||
'JackOLantern-Glow': 'glowJackolantern',
|
||||
'Gryphon-Gryphatrice': 'gryphatrice',
|
||||
'Gryphatrice-Jubilant': 'jubilantGryphatrice',
|
||||
'JackOLantern-RoyalPurple': 'royalPurpleJackolantern',
|
||||
};
|
||||
|
||||
@@ -207,6 +213,16 @@ each(specialPets, (translationString, key) => {
|
||||
};
|
||||
});
|
||||
|
||||
Object.assign(petInfo['Gryphatrice-Jubilant'], {
|
||||
canBuy () {
|
||||
return moment().isBetween(EVENTS.birthday10.start, EVENTS.birthday10.end);
|
||||
},
|
||||
currency: 'gems',
|
||||
event: 'birthday10',
|
||||
value: 60,
|
||||
purchaseType: 'pets',
|
||||
});
|
||||
|
||||
each(specialMounts, (translationString, key) => {
|
||||
mountInfo[key] = {
|
||||
key,
|
||||
|
||||
@@ -7,6 +7,7 @@ export default {
|
||||
missingTypeParam: '"req.params.type" is required.',
|
||||
missingKeyParam: '"req.params.key" is required.',
|
||||
itemNotFound: 'Item "<%= key %>" not found.',
|
||||
petNotFound: 'Pet "<%= key %>" not found.',
|
||||
questNotFound: 'Quest "<%= key %>" not found.',
|
||||
spellNotFound: 'Skill "<%= spellId %>" not found.',
|
||||
invalidQuantity: 'Quantity to purchase must be a positive whole number.',
|
||||
|
||||
@@ -7,28 +7,27 @@ import {
|
||||
} from '../content/constants';
|
||||
|
||||
const CURRENT_EVENT = find(
|
||||
EVENTS, event => moment().isBetween(event.start, event.end) && Boolean(event.season),
|
||||
EVENTS, event => moment().isBetween(event.start, event.end)
|
||||
&& ['winter', 'spring', 'summer', 'fall'].includes(event.season),
|
||||
);
|
||||
|
||||
const SHOP_OPEN = CURRENT_EVENT && ['winter', 'spring', 'summer', 'fall'].includes(CURRENT_EVENT.season);
|
||||
|
||||
export default {
|
||||
opened: SHOP_OPEN,
|
||||
opened: CURRENT_EVENT,
|
||||
|
||||
currentSeason: SHOP_OPEN ? upperFirst(CURRENT_EVENT.season) : 'Closed',
|
||||
currentSeason: CURRENT_EVENT ? upperFirst(CURRENT_EVENT.season) : 'Closed',
|
||||
|
||||
dateRange: {
|
||||
start: CURRENT_EVENT ? moment(CURRENT_EVENT.start) : moment().subtract(1, 'days').toDate(),
|
||||
end: CURRENT_EVENT ? moment(CURRENT_EVENT.end) : moment().subtract(1, 'seconds').toDate(),
|
||||
},
|
||||
|
||||
availableSets: SHOP_OPEN
|
||||
availableSets: CURRENT_EVENT
|
||||
? [
|
||||
...SEASONAL_SETS[CURRENT_EVENT.season],
|
||||
]
|
||||
: [],
|
||||
|
||||
pinnedSets: SHOP_OPEN
|
||||
pinnedSets: CURRENT_EVENT
|
||||
? {
|
||||
rogue: 'winter2023RibbonRogueSet',
|
||||
warrior: 'winter2023WalrusWarriorSet',
|
||||
@@ -36,13 +35,13 @@ export default {
|
||||
healer: 'winter2023CardinalHealerSet',
|
||||
}
|
||||
: {},
|
||||
availableSpells: SHOP_OPEN && moment().isBetween('2022-12-27T08:00-05:00', CURRENT_EVENT.end)
|
||||
availableSpells: CURRENT_EVENT && moment().isBetween('2022-12-27T08:00-05:00', CURRENT_EVENT.end)
|
||||
? [
|
||||
'snowball',
|
||||
]
|
||||
: [],
|
||||
|
||||
availableQuests: SHOP_OPEN && CURRENT_EVENT.season === 'winter'
|
||||
availableQuests: CURRENT_EVENT && CURRENT_EVENT.season === 'winter'
|
||||
? [
|
||||
'evilsanta',
|
||||
'evilsanta2',
|
||||
|
||||
@@ -13,6 +13,7 @@ import hourglassPurchase from './hourglassPurchase';
|
||||
import errorMessage from '../../libs/errorMessage';
|
||||
import { BuyGemOperation } from './buyGem';
|
||||
import { BuyQuestWithGemOperation } from './buyQuestGem';
|
||||
import { BuyPetWithGemOperation } from './buyPetGem';
|
||||
import { BuyHourglassMountOperation } from './buyMount';
|
||||
|
||||
// @TODO: remove the req option style. Dependency on express structure is an anti-pattern
|
||||
@@ -86,7 +87,12 @@ export default async function buy (
|
||||
break;
|
||||
}
|
||||
case 'pets':
|
||||
buyRes = hourglassPurchase(user, req, analytics);
|
||||
if (key === 'Gryphatrice-Jubilant') {
|
||||
const buyOp = new BuyPetWithGemOperation(user, req, analytics);
|
||||
buyRes = await buyOp.purchase();
|
||||
} else {
|
||||
buyRes = hourglassPurchase(user, req, analytics);
|
||||
}
|
||||
break;
|
||||
case 'quest': {
|
||||
const buyOp = new BuyQuestWithGoldOperation(user, req, analytics);
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
import get from 'lodash/get';
|
||||
import {
|
||||
BadRequest,
|
||||
NotFound,
|
||||
} from '../../libs/errors';
|
||||
import content from '../../content/index';
|
||||
|
||||
import errorMessage from '../../libs/errorMessage';
|
||||
import { AbstractGemItemOperation } from './abstractBuyOperation';
|
||||
|
||||
export class BuyPetWithGemOperation extends AbstractGemItemOperation { // eslint-disable-line import/prefer-default-export, max-len
|
||||
multiplePurchaseAllowed () { // eslint-disable-line class-methods-use-this
|
||||
return false;
|
||||
}
|
||||
|
||||
getItemKey () {
|
||||
return this.key;
|
||||
}
|
||||
|
||||
getItemValue (item) { // eslint-disable-line class-methods-use-this
|
||||
return item.value / 4;
|
||||
}
|
||||
|
||||
getItemType () { // eslint-disable-line class-methods-use-this
|
||||
return 'pet';
|
||||
}
|
||||
|
||||
extractAndValidateParams (user, req) {
|
||||
this.key = get(req, 'params.key');
|
||||
const { key } = this;
|
||||
if (!key) throw new BadRequest(errorMessage('missingKeyParam'));
|
||||
|
||||
const item = content.petInfo[key];
|
||||
|
||||
if (!item) throw new NotFound(errorMessage('petNotFound', { key }));
|
||||
|
||||
this.canUserPurchase(user, item);
|
||||
}
|
||||
|
||||
canUserPurchase (user, item) {
|
||||
if (item && user.items.pets[item.key]) {
|
||||
throw new BadRequest(this.i18n('petsAlreadyOwned'));
|
||||
}
|
||||
|
||||
super.canUserPurchase(user, item);
|
||||
}
|
||||
|
||||
async executeChanges (user, item, req) {
|
||||
user.items.pets[item.key] = 5;
|
||||
if (user.markModified) user.markModified('items.pets');
|
||||
|
||||
await this.subtractCurrency(user, item);
|
||||
|
||||
return [
|
||||
user.items.pets,
|
||||
this.i18n('messageBought', {
|
||||
itemText: item.text(req.language),
|
||||
}),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -251,9 +251,10 @@ export default async function unlock (user, req = {}, analytics) {
|
||||
return invalidSet(req);
|
||||
}
|
||||
|
||||
cost = getIndividualItemPrice(setType, item, req);
|
||||
|
||||
unlockedAlready = alreadyUnlocked(user, setType, firstPath);
|
||||
if (!unlockedAlready) {
|
||||
cost = getIndividualItemPrice(setType, item, req);
|
||||
}
|
||||
|
||||
// Since only an item is being unlocked here,
|
||||
// remove all the other items from the set
|
||||
|
||||
Reference in New Issue
Block a user