start fixing commong

This commit is contained in:
Matteo Pagliazzi
2019-10-09 16:51:17 +02:00
parent 9cd43db401
commit 0c27fb24a5
76 changed files with 442 additions and 275 deletions

View File

@@ -1,3 +1,4 @@
/* eslint-disable max-classes-per-file */
import _merge from 'lodash/merge';
import _get from 'lodash/get';
import i18n from '../../i18n';
@@ -61,7 +62,7 @@ export class AbstractBuyOperation {
*/
// eslint-disable-next-line no-unused-vars
i18n (key, params = {}) {
return i18n.t.apply(null, [...arguments, this.req.language]);
return i18n.t.apply(null, [...arguments, this.req.language]); // eslint-disable-line prefer-rest-params, max-len
}
/**

View File

@@ -20,7 +20,9 @@ import { BuyHourglassMountOperation } from './buyMount';
// @TODO: when we are sure buy is the only function used, let's move the buy files to a folder
export default function buy (user, req = {}, analytics, options = { quantity: 1, hourglass: false }) {
export default function buy (
user, req = {}, analytics, options = { quantity: 1, hourglass: false },
) {
const key = get(req, 'params.key');
const { hourglass } = options;
const { quantity } = options;

View File

@@ -17,7 +17,7 @@ import { AbstractGoldItemOperation } from './abstractBuyOperation';
const YIELD_EQUIPMENT_THRESHOLD = 0.6;
const YIELD_FOOD_THRESHOLD = 0.8;
export class BuyArmoireOperation extends AbstractGoldItemOperation {
export class BuyArmoireOperation extends AbstractGoldItemOperation { // eslint-disable-line import/prefer-default-export, max-len
constructor (user, req, analytics) {
super(user, req, analytics);
}
@@ -39,9 +39,15 @@ export class BuyArmoireOperation extends AbstractGoldItemOperation {
const eligibleEquipment = filter(content.gear.flat, eligible => eligible.klass === 'armoire' && !user.items.gear.owned[eligible.key]);
const armoireHasEquipment = !isEmpty(eligibleEquipment);
if (armoireHasEquipment && (armoireResult < YIELD_EQUIPMENT_THRESHOLD || !user.flags.armoireOpened)) {
if (
armoireHasEquipment
&& (armoireResult < YIELD_EQUIPMENT_THRESHOLD || !user.flags.armoireOpened)
) {
result = this._gearResult(user, eligibleEquipment);
} else if ((armoireHasEquipment && armoireResult < YIELD_FOOD_THRESHOLD) || armoireResult < 0.5) { // eslint-disable-line no-extra-parens
} else if (
(armoireHasEquipment && armoireResult < YIELD_FOOD_THRESHOLD)
|| armoireResult < 0.5
) {
result = this._foodResult(user);
} else {
result = this._experienceResult(user);
@@ -49,7 +55,8 @@ export class BuyArmoireOperation extends AbstractGoldItemOperation {
this.subtractCurrency(user, item);
let { message, armoireResp } = result;
let { message } = result;
const { armoireResp } = result;
if (!message) {
message = this.i18n('messageBought', {

View File

@@ -8,7 +8,7 @@ import {
import { AbstractGoldItemOperation } from './abstractBuyOperation';
import planGemLimits from '../../libs/planGemLimits';
export class BuyGemOperation extends AbstractGoldItemOperation {
export class BuyGemOperation extends AbstractGoldItemOperation { // eslint-disable-line import/prefer-default-export, max-len
constructor (user, req, analytics) {
super(user, req, analytics);
}
@@ -30,7 +30,8 @@ export class BuyGemOperation extends AbstractGoldItemOperation {
}
extractAndValidateParams (user, req) {
const key = this.key = get(req, 'params.key');
this.key = get(req, 'params.key');
const { key } = this.key;
if (!key) throw new BadRequest(this.i18n('missingKeyParam'));
let { convCap } = planGemLimits;

View File

@@ -5,7 +5,7 @@ import {
import { AbstractGoldItemOperation } from './abstractBuyOperation';
export class BuyHealthPotionOperation extends AbstractGoldItemOperation {
export class BuyHealthPotionOperation extends AbstractGoldItemOperation { // eslint-disable-line import/prefer-default-export, max-len
constructor (user, req, analytics) {
super(user, req, analytics);
}

View File

@@ -15,7 +15,7 @@ import { removePinnedGearAddPossibleNewOnes } from '../pinnedGearUtils';
import { AbstractGoldItemOperation } from './abstractBuyOperation';
import errorMessage from '../../libs/errorMessage';
export class BuyMarketGearOperation extends AbstractGoldItemOperation {
export class BuyMarketGearOperation extends AbstractGoldItemOperation { // eslint-disable-line import/prefer-default-export, max-len
constructor (user, req, analytics) {
super(user, req, analytics);
}
@@ -37,7 +37,8 @@ export class BuyMarketGearOperation extends AbstractGoldItemOperation {
}
extractAndValidateParams (user, req) {
const key = this.key = get(req, 'params.key');
this.key = get(req, 'params.key');
const { key } = this.key;
if (!key) throw new BadRequest(errorMessage('missingKeyParam'));
const item = content.gear.flat[key];

View File

@@ -9,7 +9,7 @@ import {
import { AbstractHourglassItemOperation } from './abstractBuyOperation';
export class BuyHourglassMountOperation extends AbstractHourglassItemOperation {
export class BuyHourglassMountOperation extends AbstractHourglassItemOperation { // eslint-disable-line import/prefer-default-export, max-len
constructor (user, req, analytics) {
super(user, req, analytics);
}
@@ -19,7 +19,8 @@ export class BuyHourglassMountOperation extends AbstractHourglassItemOperation {
}
extractAndValidateParams (user, req) {
const key = this.key = get(req, 'params.key');
this.key = get(req, 'params.key');
const { key } = this;
if (!key) throw new BadRequest(this.i18n('missingKeyParam'));

View File

@@ -40,7 +40,7 @@ export default function buyMysterySet (user, req = {}, analytics) {
if (user.markModified) user.markModified('items.gear.owned');
user.purchased.plan.consecutive.trinkets--;
user.purchased.plan.consecutive.trinkets -= 1;
return [
{ items: user.items, purchasedPlanConsecutive: user.purchased.plan.consecutive },

View File

@@ -9,7 +9,7 @@ import content from '../../content/index';
import errorMessage from '../../libs/errorMessage';
import { AbstractGemItemOperation } from './abstractBuyOperation';
export class BuyQuestWithGemOperation extends AbstractGemItemOperation {
export class BuyQuestWithGemOperation extends AbstractGemItemOperation { // eslint-disable-line import/prefer-default-export, max-len
constructor (user, req, analytics) {
super(user, req, analytics);
}
@@ -31,7 +31,8 @@ export class BuyQuestWithGemOperation extends AbstractGemItemOperation {
}
extractAndValidateParams (user, req) {
const key = this.key = get(req, 'params.key');
this.key = get(req, 'params.key');
const { key } = this.key;
if (!key) throw new BadRequest(errorMessage('missingKeyParam'));
const item = content.quests[key];
@@ -46,7 +47,10 @@ export class BuyQuestWithGemOperation extends AbstractGemItemOperation {
}
executeChanges (user, item, req) {
if (!user.items.quests[item.key] || user.items.quests[item.key] < 0) user.items.quests[item.key] = 0;
if (
!user.items.quests[item.key]
|| user.items.quests[item.key] < 0
) user.items.quests[item.key] = 0;
user.items.quests[item.key] += this.quantity;
if (user.markModified) user.markModified('items.quests');

View File

@@ -9,7 +9,7 @@ import content from '../../content/index';
import { AbstractGoldItemOperation } from './abstractBuyOperation';
import errorMessage from '../../libs/errorMessage';
export class BuyQuestWithGoldOperation extends AbstractGoldItemOperation {
export class BuyQuestWithGoldOperation extends AbstractGoldItemOperation { // eslint-disable-line import/prefer-default-export, max-len
constructor (user, req, analytics) {
super(user, req, analytics);
}
@@ -66,7 +66,10 @@ export class BuyQuestWithGoldOperation extends AbstractGoldItemOperation {
}
executeChanges (user, item, req) {
if (!user.items.quests[item.key] || user.items.quests[item.key] < 0) user.items.quests[item.key] = 0;
if (
!user.items.quests[item.key]
|| user.items.quests[item.key] < 0
) user.items.quests[item.key] = 0;
user.items.quests[item.key] += this.quantity;
if (user.markModified) user.markModified('items.quests');

View File

@@ -9,7 +9,7 @@ import {
import { AbstractGoldItemOperation } from './abstractBuyOperation';
import errorMessage from '../../libs/errorMessage';
export class BuySpellOperation extends AbstractGoldItemOperation {
export class BuySpellOperation extends AbstractGoldItemOperation { // eslint-disable-line import/prefer-default-export, max-len
constructor (user, req, analytics) {
super(user, req, analytics);
}
@@ -27,7 +27,8 @@ export class BuySpellOperation extends AbstractGoldItemOperation {
}
extractAndValidateParams (user, req) {
const key = this.key = get(req, 'params.key');
this.key = get(req, 'params.key');
const { key } = this;
if (!key) throw new BadRequest(errorMessage('missingKeyParam'));
const item = content.special[key];

View File

@@ -44,7 +44,7 @@ export default function purchaseHourglass (user, req = {}, analytics, quantity =
throw new NotAuthorized(i18n.t('notEnoughHourglasses', req.language));
}
user.purchased.plan.consecutive.trinkets--;
user.purchased.plan.consecutive.trinkets -= 1;
if (type === 'pets') {
user.items.pets[key] = 5;

View File

@@ -54,14 +54,14 @@ function purchaseItem (user, item, price, type, key) {
if (!user.items[subType][bundledKey] || user.items[subType][key] < 0) {
user.items[subType][bundledKey] = 0;
}
user.items[subType][bundledKey]++;
user.items[subType][bundledKey] += 1;
});
if (user.markModified) user.markModified(`items.${subType}`);
} else {
if (!user.items[type][key] || user.items[type][key] < 0) {
user.items[type][key] = 0;
}
user.items[type][key]++;
user.items[type][key] += 1;
if (user.markModified) user.markModified(`items.${type}`);
}
}

View File

@@ -40,7 +40,8 @@ export default function changeClass (user, req = {}, analytics) {
if (user.stats.lvl < 10) {
throw new NotAuthorized(i18n.t('lvl10ChangeClass', req.language));
} else if (!klass) {
// if no class is specified, reset points and set user.flags.classSelected to false. User will have paid 3 gems and will be prompted to select class.
// if no class is specified, reset points and set user.flags.classSelected to false.
// User will have paid 3 gems and will be prompted to select class.
balanceRemoved = resetClass(user, req);
} else if (klass === 'warrior' || klass === 'rogue' || klass === 'wizard' || klass === 'healer') {
if (user.flags.classSelected) {

View File

@@ -21,7 +21,7 @@ export default function equip (user, req = {}) {
let message;
switch (type) {
switch (type) { // eslint-disable-line default-case
case 'mount': {
if (!user.items.mounts[key]) {
throw new NotFound(i18n.t('mountNotOwned', req.language));
@@ -49,7 +49,11 @@ export default function equip (user, req = {}) {
if (user.items.gear[type][item.type] === key) {
user.items.gear[type] = {
...(user.items.gear[type].toObject ? user.items.gear[type].toObject() : user.items.gear[type]),
...(
user.items.gear[type].toObject
? user.items.gear[type].toObject()
: user.items.gear[type]
),
[item.type]: `${item.type}_base_0`,
};
if (user.markModified && type === 'owned') user.markModified('items.gear.owned');
@@ -60,7 +64,11 @@ export default function equip (user, req = {}) {
} else {
user.items.gear[type] = {
...(user.items.gear[type].toObject ? user.items.gear[type].toObject() : user.items.gear[type]),
...(
user.items.gear[type].toObject
? user.items.gear[type].toObject()
: user.items.gear[type]
),
[item.type]: item.key,
};
if (user.markModified && type === 'owned') user.markModified('items.gear.owned');

View File

@@ -90,7 +90,7 @@ export default function feed (user, req = {}) {
}
}
user.items.food[food.key]--;
user.items.food[food.key] -= 1;
if (user.markModified) user.markModified('items.food');
forEach(content.animalColorAchievements, achievement => {

View File

@@ -24,7 +24,13 @@ export default function hatch (user, req = {}) {
throw new NotFound(i18n.t('messageMissingEggPotion', req.language));
}
if ((content.hatchingPotions[hatchingPotion].premium || content.hatchingPotions[hatchingPotion].wacky) && !content.dropEggs[egg]) {
if (
(
content.hatchingPotions[hatchingPotion].premium
|| content.hatchingPotions[hatchingPotion].wacky
)
&& !content.dropEggs[egg]
) {
throw new BadRequest(i18n.t('messageInvalidEggPotionCombo', req.language));
}
@@ -35,8 +41,8 @@ export default function hatch (user, req = {}) {
}
user.items.pets[pet] = 5;
user.items.eggs[egg]--;
user.items.hatchingPotions[hatchingPotion]--;
user.items.eggs[egg] -= 1;
user.items.hatchingPotions[hatchingPotion] -= 1;
if (user.markModified) {
user.markModified('items.pets');
user.markModified('items.eggs');
@@ -45,7 +51,10 @@ export default function hatch (user, req = {}) {
forEach(content.animalColorAchievements, achievement => {
if (!user.achievements[achievement.petAchievement]) {
const petIndex = findIndex(keys(content.dropEggs), animal => isNaN(user.items.pets[`${animal}-${achievement.color}`]) || user.items.pets[`${animal}-${achievement.color}`] <= 0);
const petIndex = findIndex(
keys(content.dropEggs),
animal => Number.isNaN(user.items.pets[`${animal}-${achievement.color}`]) || user.items.pets[`${animal}-${achievement.color}`] <= 0,
);
if (petIndex === -1) {
user.achievements[achievement.petAchievement] = true;
if (user.addNotification) {

View File

@@ -37,7 +37,10 @@ export function selectGearToPin (user) {
const changes = [];
each(content.gearTypes, type => {
const found = lodashFind(content.gear.tree[type][user.stats.class], item => !user.items.gear.owned[item.key]);
const found = lodashFind(
content.gear.tree[type][user.stats.class],
item => !user.items.gear.owned[item.key],
);
if (found) changes.push(found);
});
@@ -59,11 +62,10 @@ export function addPinnedGear (user, type, path) {
export function addPinnedGearByClass (user) {
const newPinnedItems = selectGearToPin(user);
for (const item of newPinnedItems) {
newPinnedItems.forEach(item => {
const itemInfo = getItemInfo(user, 'marketGear', item);
addPinnedGear(user, itemInfo.pinType, itemInfo.path);
}
});
}
export function removeItemByPath (user, path) {
@@ -80,11 +82,10 @@ export function removeItemByPath (user, path) {
export function removePinnedGearByClass (user) {
const currentPinnedItems = selectGearToPin(user);
for (const item of currentPinnedItems) {
currentPinnedItems.forEach(item => {
const itemInfo = getItemInfo(user, 'marketGear', item);
removeItemByPath(user, itemInfo.path);
}
});
}
export function removePinnedGearAddPossibleNewOnes (user, itemPath, newItemKey) {
@@ -100,11 +101,12 @@ export function removePinnedGearAddPossibleNewOnes (user, itemPath, newItemKey)
addPinnedGearByClass(user);
// update the version, so that vue can refresh the seasonal shop
user._v++;
user._v += 1;
}
/**
* removes all pinned gear that the user already owns (like class starter gear which has been pinned before)
* removes all pinned gear that the user already owns
*(like class starter gear which has been pinned before)
* @param user
*/
export function removePinnedItemsByOwnedGear (user) {
@@ -126,9 +128,9 @@ export function togglePinnedItem (user, { item, type, path }, req = {}) {
if (!path) {
// If path isn't passed it means an item was passed
path = getItemInfo(user, type, item, officialPinnedItems, req.language).path;
path = getItemInfo(user, type, item, officialPinnedItems, req.language).path; // eslint-disable-line no-param-reassign, max-len
} else {
item = getItemByPathAndType(type, path);
item = getItemByPathAndType(type, path); // eslint-disable-line no-param-reassign
if (!item && PATHS_WITHOUT_ITEM.indexOf(path) === -1) {
// path not exists in our content structure

View File

@@ -16,6 +16,8 @@ function markNotificationAsRead (user, cardType) {
&& notification.data
&& notification.data.card === cardType
) return true;
return false;
});
if (indexToRemove !== -1) user.notifications.splice(indexToRemove, 1);

View File

@@ -97,7 +97,7 @@ export default function rebirth (user, tasks = [], req = {}, analytics) {
user.achievements.rebirths = 1;
user.achievements.rebirthLevel = lvl;
} else if (lvl > user.achievements.rebirthLevel || lvl === MAX_LEVEL) {
user.achievements.rebirths++;
user.achievements.rebirths += 1;
user.achievements.rebirthLevel = lvl;
}

View File

@@ -8,13 +8,14 @@ import {
import splitWhitespace from '../libs/splitWhitespace';
export default function releaseBoth (user, req = {}) {
let animal;
if (!user.achievements.triadBingo) {
throw new NotAuthorized(i18n.t('notEnoughPetsMounts', req.language));
}
if (beastMasterProgress(user.items.pets) !== 90 || mountMasterProgress(user.items.mounts) !== 90) {
if (
beastMasterProgress(user.items.pets) !== 90
|| mountMasterProgress(user.items.mounts) !== 90
) {
throw new NotAuthorized(i18n.t('notEnoughPetsMounts', req.language));
}
@@ -49,7 +50,7 @@ export default function releaseBoth (user, req = {}) {
user.items.currentPet = '';
}
for (animal in content.pets) {
Object.keys(content.pets).forEach(animal => {
if (user.items.pets[animal] === -1) {
giveTriadBingo = false;
} else if (!user.items.pets[animal]) {
@@ -61,7 +62,8 @@ export default function releaseBoth (user, req = {}) {
user.items.pets[animal] = 0;
user.items.mounts[animal] = null;
}
});
if (user.markModified) {
user.markModified('items.pets');
user.markModified('items.mounts');
@@ -71,21 +73,21 @@ export default function releaseBoth (user, req = {}) {
if (!user.achievements.beastMasterCount) {
user.achievements.beastMasterCount = 0;
}
user.achievements.beastMasterCount++;
user.achievements.beastMasterCount += 1;
}
if (giveMountMasterAchievement) {
if (!user.achievements.mountMasterCount) {
user.achievements.mountMasterCount = 0;
}
user.achievements.mountMasterCount++;
user.achievements.mountMasterCount += 1;
}
if (giveTriadBingo) {
if (!user.achievements.triadBingoCount) {
user.achievements.triadBingoCount = 0;
}
user.achievements.triadBingoCount++;
user.achievements.triadBingoCount += 1;
}
return [

View File

@@ -24,19 +24,20 @@ export default function releaseMounts (user, req = {}, analytics) {
user.items.currentMount = '';
}
for (const mount in content.pets) {
Object.keys(content.pets).forEach(mount => {
if (user.items.mounts[mount] === null || user.items.mounts[mount] === undefined) {
giveMountMasterAchievement = false;
}
user.items.mounts[mount] = null;
}
});
if (user.markModified) user.markModified('items.mounts');
if (giveMountMasterAchievement) {
if (!user.achievements.mountMasterCount) {
user.achievements.mountMasterCount = 0;
}
user.achievements.mountMasterCount++;
user.achievements.mountMasterCount += 1;
}
if (analytics) {

View File

@@ -24,19 +24,20 @@ export default function releasePets (user, req = {}, analytics) {
user.items.currentPet = '';
}
for (const pet in content.pets) {
Object.keys(content.pets).forEach(pet => {
if (!user.items.pets[pet]) {
giveBeastMasterAchievement = false;
}
user.items.pets[pet] = 0;
}
});
if (user.markModified) user.markModified('items.pets');
if (giveBeastMasterAchievement) {
if (!user.achievements.beastMasterCount) {
user.achievements.beastMasterCount = 0;
}
user.achievements.beastMasterCount++;
user.achievements.beastMasterCount += 1;
}
if (analytics) {

View File

@@ -9,7 +9,7 @@ export default function reroll (user, tasks = [], req = {}, analytics) {
throw new NotAuthorized(i18n.t('notEnoughGems', req.language));
}
user.balance--;
user.balance -= 1;
user.stats.hp = 50;
each(tasks, task => {

View File

@@ -24,7 +24,7 @@ export default function revive (user, req = {}, analytics) {
});
if (user.stats.lvl > 1) {
user.stats.lvl--;
user.stats.lvl -= 1;
}
const lostStat = randomVal(reduce(['str', 'con', 'per', 'int'], (m, k) => {
@@ -37,7 +37,7 @@ export default function revive (user, req = {}, analytics) {
});
if (lostStat) {
user.stats[lostStat]--;
user.stats[lostStat] -= 1;
}
const base = user.items.gear.owned;
@@ -68,9 +68,11 @@ export default function revive (user, req = {}, analytics) {
const itemIsArmoire = itm.klass === 'armoire';
if (itemHasValueOrWarrior0 && (itemClassEqualsUserClass || itemIsSpecial || itemIsArmoire)) {
if (
itemHasValueOrWarrior0
&& (itemClassEqualsUserClass || itemIsSpecial || itemIsArmoire)
) {
losableItems[key] = key;
return losableItems[key];
}
}
}

View File

@@ -28,7 +28,7 @@ function _getTaskValue (taskValue) {
function _calculateDelta (task, direction, cron) {
// Min/max on task redness
const currVal = _getTaskValue(task.value);
let nextDelta = Math.pow(0.9747, currVal) * (direction === 'down' ? -1 : 1);
let nextDelta = (0.9747 ** currVal) * (direction === 'down' ? -1 : 1);
// Checklists
if (task.checklist && task.checklist.length > 0) {
@@ -52,13 +52,13 @@ function _calculateDelta (task, direction, cron) {
// it will be a bit off
function _calculateReverseDelta (task, direction) {
const currVal = _getTaskValue(task.value);
let testVal = currVal + Math.pow(0.9747, currVal) * (direction === 'down' ? -1 : 1);
let testVal = currVal + (0.9747 ** currVal) * (direction === 'down' ? -1 : 1);
// Now keep moving closer to the original value until we get "close enough"
// Check how close we are to the original value by computing the delta off our guess
// and looking at the difference between that and our current value.
while (true) { // eslint-disable-line no-constant-condition
const calc = testVal + Math.pow(0.9747, testVal);
const calc = testVal + (0.9747 ** testVal);
const diff = currVal - calc;
if (Math.abs(diff) < CLOSE_ENOUGH) break;
@@ -84,7 +84,7 @@ function _calculateReverseDelta (task, direction) {
}
function _gainMP (user, val) {
val *= user._tmp.crit || 1;
val *= user._tmp.crit || 1; // eslint-disable-line no-param-reassign
user.stats.mp += val;
if (user.stats.mp >= statsComputed(user).maxMP) user.stats.mp = statsComputed(user).maxMP;
@@ -125,7 +125,8 @@ function _addPoints (user, task, stats, direction, delta) {
const streakBonus = currStreak / 100 + 1; // eg, 1-day streak is 1.01, 2-day is 1.02, etc
const afterStreak = gpMod * streakBonus;
if (currStreak > 0 && gpMod > 0) {
user._tmp.streakBonus = afterStreak - gpMod; // keep this on-hand for later, so we can notify streak-bonus
// keep this on-hand for later, so we can notify streak-bonus
user._tmp.streakBonus = afterStreak - gpMod;
}
stats.gp += afterStreak;
@@ -194,9 +195,13 @@ export default function scoreTask (options = {}, req = {}) {
exp: user.stats.exp,
};
if (task.group && task.group.approval && task.group.approval.required && !task.group.approval.approved) return 0;
if (
task.group && task.group.approval && task.group.approval.required
&& !task.group.approval.approved
) return 0;
// This is for setting one-time temporary flags, such as streakBonus or itemDropped. Useful for notifying
// This is for setting one-time temporary flags,
// such as streakBonus or itemDropped. Useful for notifying
// the API consumer, then cleared afterwards
user._tmp = {};
@@ -236,7 +241,8 @@ export default function scoreTask (options = {}, req = {}) {
lastHistoryEntry.value = task.value;
lastHistoryEntry.date = Number(new Date());
// @TODO remove this extra check after migration has run to set scoredUp and scoredDown in every task
// @TODO remove this extra check after migration
// has run to set scoredUp and scoredDown in every task
lastHistoryEntry.scoredUp = lastHistoryEntry.scoredUp || 0;
lastHistoryEntry.scoredDown = lastHistoryEntry.scoredDown || 0;
@@ -265,7 +271,8 @@ export default function scoreTask (options = {}, req = {}) {
} else {
delta += _changeTaskValue(user, task, direction, times, cron);
if (direction === 'down') delta = _calculateDelta(task, direction, cron); // recalculate delta for unchecking so the gp and exp come out correctly
_addPoints(user, task, stats, direction, delta); // obviously for delta>0, but also a trick to undo accidental checkboxes
// obviously for delta>0, but also a trick to undo accidental checkboxes
_addPoints(user, task, stats, direction, delta);
_gainMP(user, max([1, 0.01 * statsComputed(user).maxMP]) * (direction === 'down' ? -1 : 1));
if (direction === 'up') {
@@ -286,7 +293,9 @@ export default function scoreTask (options = {}, req = {}) {
task.history.push(historyEntry);
} else if (direction === 'down') {
// Remove a streak achievement if streak was a multiple of 21 and the daily was undone
if (task.streak !== 0 && task.streak % 21 === 0) user.achievements.streak = user.achievements.streak ? user.achievements.streak - 1 : 0;
if (task.streak !== 0 && task.streak % 21 === 0) {
user.achievements.streak = user.achievements.streak ? user.achievements.streak - 1 : 0;
}
task.streak -= 1;
task.completed = false;

View File

@@ -22,10 +22,10 @@ export default function allocate (user, req = {}) {
}
if (user.stats.points > 0) {
user.stats[stat]++;
user.stats.points--;
user.stats[stat] += 1;
user.stats.points -= 1;
if (stat === 'int') {
user.stats.mp++;
user.stats.mp += 1;
}
} else {
throw new NotAuthorized(i18n.t('notEnoughAttrPoints', req.language));

View File

@@ -34,11 +34,11 @@ export default function allocateBulk (user, req = {}) {
throw new NotAuthorized(i18n.t('notEnoughAttrPoints', req.language));
}
for (const [stat, value] of Object.entries(stats)) {
Object.entries(stats).forEach(([stat, value]) => {
user.stats[stat] += value;
user.stats.points -= value;
if (stat === 'int') user.stats.mp += value;
}
});
return [
user.stats,

View File

@@ -45,13 +45,14 @@ export default function unlock (user, req = {}, analytics) {
each(setPaths, singlePath => {
if (get(user, `purchased.${singlePath}`) === true) {
alreadyOwnedItems++;
alreadyOwnedItems += 1;
}
});
if (alreadyOwnedItems === setPaths.length) {
throw new NotAuthorized(i18n.t('alreadyUnlocked', req.language));
// TODO write math formula to check if buying the full set is cheaper than the items individually
// TODO write math formula to check if buying
// the full set is cheaper than the items individually
// (item cost * number of remaining items) < setCost`
} /* else if (alreadyOwnedItems > 0) {
throw new NotAuthorized(i18n.t('alreadyUnlockedPart', req.language));