Merge remote-tracking branch 'origin/develop' into negue/ui/setting

# Conflicts:
#	website/client/src/components/header/notificationsDropdown.vue
This commit is contained in:
negue
2023-01-30 22:47:05 +01:00
126 changed files with 5435 additions and 1358 deletions
@@ -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);
},
},
};
+1 -1
View File
@@ -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',
+16
View File
@@ -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',
+7 -1
View File
@@ -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),
}),
];
}
}
+3 -2
View File
@@ -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