Merge branch 'develop' into release

This commit is contained in:
Sabe Jones
2019-12-19 16:55:10 -06:00
303 changed files with 28278 additions and 21288 deletions
+8
View File
@@ -24,3 +24,11 @@ export const SUPPORTED_SOCIAL_NETWORKS = [
export const GUILDS_PER_PAGE = 30; // number of guilds to return per page when using pagination
export const PARTY_LIMIT_MEMBERS = 30;
export const MINIMUM_PASSWORD_LENGTH = 8;
export const TRANSFORMATION_DEBUFFS_LIST = {
snowball: 'salt',
spookySparkles: 'opaquePotion',
shinySeed: 'petalFreePotion',
seafoam: 'sand',
};
@@ -180,6 +180,35 @@ const basicAchievs = {
};
Object.assign(achievementsData, basicAchievs);
const onboardingAchievs = {
createdTask: {
icon: 'achievement-createdTask',
titleKey: 'achievementCreatedTask',
textKey: 'achievementCreatedTaskText',
},
completedTask: {
icon: 'achievement-completedTask',
titleKey: 'achievementCompletedTask',
textKey: 'achievementCompletedTaskText',
},
hatchedPet: {
icon: 'achievement-hatchedPet',
titleKey: 'achievementHatchedPet',
textKey: 'achievementHatchedPetText',
},
fedPet: {
icon: 'achievement-fedPet',
titleKey: 'achievementFedPet',
textKey: 'achievementFedPetText',
},
purchasedEquipment: {
icon: 'achievement-purchasedEquipment',
titleKey: 'achievementPurchasedEquipment',
textKey: 'achievementPurchasedEquipmentText',
},
};
Object.assign(achievementsData, onboardingAchievs);
const specialAchievs = {
contributor: {
icon: 'achievement-boot',
+9
View File
@@ -2,6 +2,7 @@ import each from 'lodash/each';
import t from './translation';
import { NotAuthorized } from '../libs/errors';
import statsComputed from '../libs/statsComputed'; // eslint-disable-line import/no-cycle
import setDebuffPotionItems from '../libs/setDebuffPotionItems'; // eslint-disable-line import/no-cycle
import crit from '../fns/crit'; // eslint-disable-line import/no-cycle
import updateStats from '../fns/updateStats';
@@ -287,6 +288,7 @@ spells.special = {
if (!target.achievements.snowball) target.achievements.snowball = 0;
target.achievements.snowball += 1;
user.items.special.snowball -= 1;
setDebuffPotionItems(user);
},
},
salt: {
@@ -300,6 +302,7 @@ spells.special = {
cast (user) {
user.stats.buffs.snowball = false;
user.stats.gp -= 5;
setDebuffPotionItems(user);
},
},
spookySparkles: {
@@ -318,6 +321,7 @@ spells.special = {
if (!target.achievements.spookySparkles) target.achievements.spookySparkles = 0;
target.achievements.spookySparkles += 1;
user.items.special.spookySparkles -= 1;
setDebuffPotionItems(user);
},
},
opaquePotion: {
@@ -331,6 +335,7 @@ spells.special = {
cast (user) {
user.stats.buffs.spookySparkles = false;
user.stats.gp -= 5;
setDebuffPotionItems(user);
},
},
shinySeed: {
@@ -349,6 +354,7 @@ spells.special = {
if (!target.achievements.shinySeed) target.achievements.shinySeed = 0;
target.achievements.shinySeed += 1;
user.items.special.shinySeed -= 1;
setDebuffPotionItems(user);
},
},
petalFreePotion: {
@@ -362,6 +368,7 @@ spells.special = {
cast (user) {
user.stats.buffs.shinySeed = false;
user.stats.gp -= 5;
setDebuffPotionItems(user);
},
},
seafoam: {
@@ -380,6 +387,7 @@ spells.special = {
if (!target.achievements.seafoam) target.achievements.seafoam = 0;
target.achievements.seafoam += 1;
user.items.special.seafoam -= 1;
setDebuffPotionItems(user);
},
},
sand: {
@@ -393,6 +401,7 @@ spells.special = {
cast (user) {
user.stats.buffs.seafoam = false;
user.stats.gp -= 5;
setDebuffPotionItems(user);
},
},
nye: {
+68 -86
View File
@@ -1,78 +1,30 @@
// When using a common module from the website or the server NEVER import the module directly
// but access it through `api` (the main common) module,
// otherwise you would require the non transpiled version of the file in production.
import content from './content/index';
import * as errors from './libs/errors';
import i18n from './i18n';
import commonErrors from './errors/commonErrorMessages';
import apiErrors from './errors/apiErrorMessages';
// TODO under api.libs.cron?
import { shouldDo, daysSince, DAY_MAPPING } from './cron';
import {
MAX_HEALTH,
MAX_LEVEL,
MAX_STAT_POINTS,
MAX_INCENTIVES,
TAVERN_ID,
LARGE_GROUP_COUNT_MESSAGE_CUTOFF,
MAX_SUMMARY_SIZE_FOR_GUILDS,
MAX_SUMMARY_SIZE_FOR_CHALLENGES,
MIN_SHORTNAME_SIZE_FOR_CHALLENGES,
SUPPORTED_SOCIAL_NETWORKS,
GUILDS_PER_PAGE,
PARTY_LIMIT_MEMBERS,
CHAT_FLAG_LIMIT_FOR_HIDING,
CHAT_FLAG_FROM_MOD,
CHAT_FLAG_FROM_SHADOW_MUTE,
CHAT_FLAG_LIMIT_FOR_HIDING,
GUILDS_PER_PAGE,
LARGE_GROUP_COUNT_MESSAGE_CUTOFF,
MAX_HEALTH,
MAX_INCENTIVES,
MAX_LEVEL,
MAX_STAT_POINTS,
MAX_SUMMARY_SIZE_FOR_CHALLENGES,
MAX_SUMMARY_SIZE_FOR_GUILDS,
MIN_SHORTNAME_SIZE_FOR_CHALLENGES,
PARTY_LIMIT_MEMBERS,
MINIMUM_PASSWORD_LENGTH,
SUPPORTED_SOCIAL_NETWORKS,
TAVERN_ID,
} from './constants';
// TODO under api.libs.statHelpers?
import * as statHelpers from './statHelpers';
import splitWhitespace from './libs/splitWhitespace';
import refPush from './libs/refPush';
import planGemLimits from './libs/planGemLimits';
import preenTodos from './libs/preenTodos';
import updateStore from './libs/updateStore';
import inAppRewards from './libs/inAppRewards';
import uuid from './libs/uuid';
import taskDefaults from './libs/taskDefaults';
import percent from './libs/percent';
import gold from './libs/gold';
import silver from './libs/silver';
import noTags from './libs/noTags';
import appliedTags from './libs/appliedTags';
import pickDeep from './libs/pickDeep';
import content from './content/index';
import * as count from './count';
import statsComputed from './libs/statsComputed';
import shops from './libs/shops';
import achievements from './libs/achievements';
import randomVal from './libs/randomVal';
import hasClass from './libs/hasClass';
// TODO under api.libs.cron?
import { daysSince, DAY_MAPPING, shouldDo } from './cron';
import apiErrors from './errors/apiErrorMessages';
import commonErrors from './errors/commonErrorMessages';
import autoAllocate from './fns/autoAllocate';
import crit from './fns/crit';
import handleTwoHanded from './fns/handleTwoHanded';
@@ -81,33 +33,59 @@ import randomDrop from './fns/randomDrop';
import resetGear from './fns/resetGear';
import ultimateGear from './fns/ultimateGear';
import updateStats from './fns/updateStats';
import scoreTask from './ops/scoreTask';
import sleep from './ops/sleep';
import allocateNow from './ops/stats/allocateNow';
import allocate from './ops/stats/allocate';
import allocateBulk from './ops/stats/allocateBulk';
import i18n from './i18n';
import achievements from './libs/achievements';
import appliedTags from './libs/appliedTags';
import * as errors from './libs/errors';
import getDebuffPotionItems from './libs/getDebuffPotionItems';
import gold from './libs/gold';
import hasClass from './libs/hasClass';
import inAppRewards from './libs/inAppRewards';
import noTags from './libs/noTags';
import * as onboarding from './libs/onboarding';
import percent from './libs/percent';
import pickDeep from './libs/pickDeep';
import planGemLimits from './libs/planGemLimits';
import preenTodos from './libs/preenTodos';
import randomVal from './libs/randomVal';
import refPush from './libs/refPush';
import setDebuffPotionItems from './libs/setDebuffPotionItems';
import shops from './libs/shops';
import silver from './libs/silver';
import splitWhitespace from './libs/splitWhitespace';
import statsComputed from './libs/statsComputed';
import taskDefaults from './libs/taskDefaults';
import updateStore from './libs/updateStore';
import uuid from './libs/uuid';
import blockUser from './ops/blockUser';
import buy from './ops/buy/buy';
import hatch from './ops/hatch';
import feed from './ops/feed';
import equip from './ops/equip';
import changeClass from './ops/changeClass';
import disableClasses from './ops/disableClasses';
import readCard from './ops/readCard';
import equip from './ops/equip';
import feed from './ops/feed';
import hatch from './ops/hatch';
import markPmsRead from './ops/markPMSRead';
import openMysteryItem from './ops/openMysteryItem';
import releasePets from './ops/releasePets';
import * as pinnedGearUtils from './ops/pinnedGearUtils';
import readCard from './ops/readCard';
import rebirth from './ops/rebirth';
import releaseBoth from './ops/releaseBoth';
import releaseMounts from './ops/releaseMounts';
import updateTask from './ops/updateTask';
import sell from './ops/sell';
import unlock from './ops/unlock';
import revive from './ops/revive';
import rebirth from './ops/rebirth';
import blockUser from './ops/blockUser';
import releasePets from './ops/releasePets';
import reroll from './ops/reroll';
import reset from './ops/reset';
import markPmsRead from './ops/markPMSRead';
import * as pinnedGearUtils from './ops/pinnedGearUtils';
import revive from './ops/revive';
import scoreTask from './ops/scoreTask';
import sell from './ops/sell';
import sleep from './ops/sleep';
import allocate from './ops/stats/allocate';
import allocateBulk from './ops/stats/allocateBulk';
import allocateNow from './ops/stats/allocateNow';
import unlock from './ops/unlock';
import updateTask from './ops/updateTask';
// TODO under api.libs.statHelpers?
import * as statHelpers from './statHelpers';
const api = {};
api.content = content;
@@ -129,6 +107,7 @@ api.constants = {
CHAT_FLAG_LIMIT_FOR_HIDING,
CHAT_FLAG_FROM_MOD,
CHAT_FLAG_FROM_SHADOW_MUTE,
MINIMUM_PASSWORD_LENGTH,
};
// TODO Move these under api.constants
api.maxLevel = MAX_LEVEL;
@@ -158,6 +137,9 @@ api.shops = shops;
api.achievements = achievements;
api.randomVal = randomVal;
api.hasClass = hasClass;
api.onboarding = onboarding;
api.setDebuffPotionItems = setDebuffPotionItems;
api.getDebuffPotionItems = getDebuffPotionItems;
api.fns = {
autoAllocate,
@@ -241,6 +241,18 @@ function _getBasicAchievements (user, language) {
return result;
}
function _getOnboardingAchievements (user, language) {
const result = {};
_addSimple(result, user, { path: 'createdTask', language });
_addSimple(result, user, { path: 'completedTask', language });
_addSimple(result, user, { path: 'hatchedPet', language });
_addSimple(result, user, { path: 'fedPet', language });
_addSimple(result, user, { path: 'purchasedEquipment', language });
return result;
}
function _getSeasonalAchievements (user, language) {
const result = {};
@@ -321,6 +333,10 @@ achievs.getAchievementsForProfile = function getAchievementsForProfile (user, la
label: 'Basic',
achievements: _getBasicAchievements(user, language),
},
onboarding: {
label: 'Onboarding',
achievements: _getOnboardingAchievements(user, language),
},
seasonal: {
label: 'Seasonal',
achievements: _getSeasonalAchievements(user, language),
@@ -0,0 +1,21 @@
import { TRANSFORMATION_DEBUFFS_LIST } from '../constants';
export default function getDebuffPotionItems (user) {
const items = [];
const userBuffs = user.stats.buffs;
if (user) {
for (const key in TRANSFORMATION_DEBUFFS_LIST) {
if (userBuffs[key]) {
const debuff = TRANSFORMATION_DEBUFFS_LIST[key];
const item = {
path: `spells.special.${debuff}`,
type: 'debuffPotion',
};
items.push(item);
}
}
}
return items;
}
+19
View File
@@ -177,6 +177,25 @@ export default function getItemInfo (user, type, item, officialPinnedItems, lang
pinType: 'seasonalSpell',
};
break;
case 'debuffPotion':
itemInfo = {
key: item.key,
mana: item.mana,
cast: item.cast,
immediateUse: item.immediateUse,
target: item.target,
text: item.text(language),
notes: item.notes(language),
value: item.value,
type: 'debuffPotion',
currency: 'gold',
locked: false,
purchaseType: 'debuffPotion',
class: `shop_${item.key}`,
path: `spells.special.${item.key}`,
pinType: 'debuffPotion',
};
break;
case 'seasonalQuest':
itemInfo = {
key: item.key,
+31
View File
@@ -0,0 +1,31 @@
import moment from 'moment';
const BEGIN_DATE = moment('2019-12-18');
// Only users that signed up after the BEGIN DATE should see the onboarding
export function hasActiveOnboarding (user) {
return BEGIN_DATE.isBefore(user.auth.timestamps.created);
}
export function hasCompletedOnboarding (user) {
return (
user.achievements.createdTask === true
&& user.achievements.completedTask === true
&& user.achievements.hatchedPet === true
&& user.achievements.fedPet === true
&& user.achievements.purchasedEquipment === true
);
}
export function onOnboardingComplete (user) {
// Award gold
user.stats.gp += 100;
}
// Add notification and awards (server)
export function checkOnboardingStatus (user) {
if (hasActiveOnboarding(user) && hasCompletedOnboarding(user) && user.addNotification) {
user.addNotification('ONBOARDING_COMPLETE');
onOnboardingComplete(user);
}
}
@@ -0,0 +1,30 @@
import getDebuffPotionItems from './getDebuffPotionItems';
function clearDebuffPotion (user) {
return user.pinnedItems.filter(item => item.type !== 'debuffPotion');
}
export default function setDebuffPotionItems (user) {
user.pinnedItems = clearDebuffPotion(user);
const debuffPotionItems = getDebuffPotionItems(user);
if (debuffPotionItems.length) {
let isPresent = false;
const isUserHaveDebuffInPinnedItems = user.pinnedItems.find(pinnedItem => {
debuffPotionItems.forEach(debuffPotion => {
if (!isPresent) {
isPresent = debuffPotion.path === pinnedItem.path;
}
});
return isPresent;
});
if (!isUserHaveDebuffInPinnedItems) {
user.pinnedItems.push(...debuffPotionItems);
}
}
return user;
}
@@ -2,6 +2,7 @@ import get from 'lodash/get';
import pick from 'lodash/pick';
import content from '../../content/index';
import splitWhitespace from '../../libs/splitWhitespace';
import { checkOnboardingStatus } from '../../libs/onboarding';
import {
BadRequest,
NotAuthorized,
@@ -67,6 +68,11 @@ export class BuyMarketGearOperation extends AbstractGoldItemOperation { // eslin
message = handleTwoHanded(user, item, undefined, req);
}
if (!user.achievements.purchasedEquipment && user.addAchievement) {
user.addAchievement('purchasedEquipment');
checkOnboardingStatus(user);
}
removePinnedGearAddPossibleNewOnes(user, `gear.flat.${item.key}`, item.key);
if (item.last) ultimateGear(user);
+6
View File
@@ -11,6 +11,7 @@ import {
NotFound,
} from '../libs/errors';
import errorMessage from '../libs/errorMessage';
import { checkOnboardingStatus } from '../libs/onboarding';
function evolve (user, pet, req) {
user.items.pets[pet.key] = -1;
@@ -88,6 +89,11 @@ export default function feed (user, req = {}) {
if (userPets[pet.key] >= 50 && !user.items.mounts[pet.key]) {
message = evolve(user, pet, req);
}
if (!user.achievements.fedPet && user.addAchievement) {
user.addAchievement('fedPet');
checkOnboardingStatus(user);
}
}
user.items.food[food.key] -= 1;
+6
View File
@@ -11,6 +11,7 @@ import {
NotFound,
} from '../libs/errors';
import errorMessage from '../libs/errorMessage';
import { checkOnboardingStatus } from '../libs/onboarding';
export default function hatch (user, req = {}) {
const egg = get(req, 'params.egg');
@@ -49,6 +50,11 @@ export default function hatch (user, req = {}) {
user.markModified('items.hatchingPotions');
}
if (!user.achievements.hatchedPet && user.addAchievement) {
user.addAchievement('hatchedPet');
checkOnboardingStatus(user);
}
forEach(content.animalColorAchievements, achievement => {
if (!user.achievements[achievement.petAchievement]) {
const petIndex = findIndex(
+3 -2
View File
@@ -143,8 +143,9 @@ export function togglePinnedItem (user, { item, type, path }, req = {}) {
}
if (path === 'armoire' || path === 'potion') {
throw new BadRequest(i18n.t('cannotUnpinArmoirPotion', req.language));
if (path === 'armoire' || path === 'potion' || type === 'debuffPotion') {
// @TODO: take into considertation debuffPotion type in message
throw new BadRequest(i18n.t('cannotUnpinItem', req.language));
}
const isOfficialPinned = pathExistsInArray(officialPinnedItems, path) !== -1;
+7
View File
@@ -9,6 +9,7 @@ import i18n from '../i18n';
import updateStats from '../fns/updateStats';
import crit from '../fns/crit';
import statsComputed from '../libs/statsComputed';
import { checkOnboardingStatus } from '../libs/onboarding';
const MAX_TASK_VALUE = 21.27;
const MIN_TASK_VALUE = -47.27;
@@ -343,5 +344,11 @@ export default function scoreTask (options = {}, req = {}) {
req.yesterDailyScored = task.yesterDailyScored;
updateStats(user, stats, req);
if (!user.achievements.completedTask && cron === false && direction === 'up' && user.addAchievement) {
user.addAchievement('completedTask');
checkOnboardingStatus(user);
}
return [delta];
}