mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-18 15:17:25 +01:00
refactor: adjust randomDrop to use wrapped random function
This commit is contained in:
@@ -16,17 +16,14 @@ describe('common.fns.randomDrop', () => {
|
|||||||
user = generateUser();
|
user = generateUser();
|
||||||
user._tmp = user._tmp ? user._tmp : {};
|
user._tmp = user._tmp ? user._tmp : {};
|
||||||
task = generateTodo({ userId: user._id });
|
task = generateTodo({ userId: user._id });
|
||||||
predictableRandom = () => {
|
predictableRandom = sandbox.stub().returns(0.5);
|
||||||
return 0.5;
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('drops an item for the user.party.quest.progress', () => {
|
it('drops an item for the user.party.quest.progress', () => {
|
||||||
expect(user.party.quest.progress.collectedItems).to.eql(0);
|
expect(user.party.quest.progress.collectedItems).to.eql(0);
|
||||||
user.party.quest.key = 'vice2';
|
user.party.quest.key = 'vice2';
|
||||||
predictableRandom = () => {
|
predictableRandom.returns(0.0001);
|
||||||
return 0.0001;
|
|
||||||
};
|
|
||||||
randomDrop(user, { task, predictableRandom });
|
randomDrop(user, { task, predictableRandom });
|
||||||
expect(user.party.quest.progress.collectedItems).to.eql(1);
|
expect(user.party.quest.progress.collectedItems).to.eql(1);
|
||||||
expect(user._tmp.quest.collection).to.eql(1);
|
expect(user._tmp.quest.collection).to.eql(1);
|
||||||
@@ -50,9 +47,8 @@ describe('common.fns.randomDrop', () => {
|
|||||||
it('drops something when the task is a todo', () => {
|
it('drops something when the task is a todo', () => {
|
||||||
expect(user._tmp).to.eql({});
|
expect(user._tmp).to.eql({});
|
||||||
user.flags.dropsEnabled = true;
|
user.flags.dropsEnabled = true;
|
||||||
predictableRandom = () => {
|
predictableRandom.returns(0.1);
|
||||||
return 0.1;
|
|
||||||
};
|
|
||||||
randomDrop(user, { task, predictableRandom });
|
randomDrop(user, { task, predictableRandom });
|
||||||
expect(user._tmp).to.not.eql({});
|
expect(user._tmp).to.not.eql({});
|
||||||
});
|
});
|
||||||
@@ -61,9 +57,8 @@ describe('common.fns.randomDrop', () => {
|
|||||||
task = generateHabit({ userId: user._id });
|
task = generateHabit({ userId: user._id });
|
||||||
expect(user._tmp).to.eql({});
|
expect(user._tmp).to.eql({});
|
||||||
user.flags.dropsEnabled = true;
|
user.flags.dropsEnabled = true;
|
||||||
predictableRandom = () => {
|
predictableRandom.returns(0.1);
|
||||||
return 0.1;
|
|
||||||
};
|
|
||||||
randomDrop(user, { task, predictableRandom });
|
randomDrop(user, { task, predictableRandom });
|
||||||
expect(user._tmp).to.not.eql({});
|
expect(user._tmp).to.not.eql({});
|
||||||
});
|
});
|
||||||
@@ -72,9 +67,8 @@ describe('common.fns.randomDrop', () => {
|
|||||||
task = generateDaily({ userId: user._id });
|
task = generateDaily({ userId: user._id });
|
||||||
expect(user._tmp).to.eql({});
|
expect(user._tmp).to.eql({});
|
||||||
user.flags.dropsEnabled = true;
|
user.flags.dropsEnabled = true;
|
||||||
predictableRandom = () => {
|
predictableRandom.returns(0.1);
|
||||||
return 0.1;
|
|
||||||
};
|
|
||||||
randomDrop(user, { task, predictableRandom });
|
randomDrop(user, { task, predictableRandom });
|
||||||
expect(user._tmp).to.not.eql({});
|
expect(user._tmp).to.not.eql({});
|
||||||
});
|
});
|
||||||
@@ -83,34 +77,30 @@ describe('common.fns.randomDrop', () => {
|
|||||||
task = generateReward({ userId: user._id });
|
task = generateReward({ userId: user._id });
|
||||||
expect(user._tmp).to.eql({});
|
expect(user._tmp).to.eql({});
|
||||||
user.flags.dropsEnabled = true;
|
user.flags.dropsEnabled = true;
|
||||||
predictableRandom = () => {
|
predictableRandom.returns(0.1);
|
||||||
return 0.1;
|
|
||||||
};
|
|
||||||
randomDrop(user, { task, predictableRandom });
|
randomDrop(user, { task, predictableRandom });
|
||||||
expect(user._tmp).to.not.eql({});
|
expect(user._tmp).to.not.eql({});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('drops food', () => {
|
it('drops food', () => {
|
||||||
predictableRandom = () => {
|
predictableRandom.returns(0.65);
|
||||||
return 0.65;
|
|
||||||
};
|
|
||||||
randomDrop(user, { task, predictableRandom });
|
randomDrop(user, { task, predictableRandom });
|
||||||
expect(user._tmp.drop.type).to.eql('Food');
|
expect(user._tmp.drop.type).to.eql('Food');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('drops eggs', () => {
|
it('drops eggs', () => {
|
||||||
predictableRandom = () => {
|
predictableRandom.returns(0.35);
|
||||||
return 0.35;
|
|
||||||
};
|
|
||||||
randomDrop(user, { task, predictableRandom });
|
randomDrop(user, { task, predictableRandom });
|
||||||
expect(user._tmp.drop.type).to.eql('Egg');
|
expect(user._tmp.drop.type).to.eql('Egg');
|
||||||
});
|
});
|
||||||
|
|
||||||
context('drops hatching potion', () => {
|
context('drops hatching potion', () => {
|
||||||
it('drops a very rare potion', () => {
|
it('drops a very rare potion', () => {
|
||||||
predictableRandom = () => {
|
predictableRandom.returns(0.01);
|
||||||
return 0.01;
|
|
||||||
};
|
|
||||||
randomDrop(user, { task, predictableRandom });
|
randomDrop(user, { task, predictableRandom });
|
||||||
expect(user._tmp.drop.type).to.eql('HatchingPotion');
|
expect(user._tmp.drop.type).to.eql('HatchingPotion');
|
||||||
expect(user._tmp.drop.value).to.eql(5);
|
expect(user._tmp.drop.value).to.eql(5);
|
||||||
@@ -118,9 +108,8 @@ describe('common.fns.randomDrop', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('drops a rare potion', () => {
|
it('drops a rare potion', () => {
|
||||||
predictableRandom = () => {
|
predictableRandom.returns(0.08);
|
||||||
return 0.08;
|
|
||||||
};
|
|
||||||
randomDrop(user, { task, predictableRandom });
|
randomDrop(user, { task, predictableRandom });
|
||||||
expect(user._tmp.drop.type).to.eql('HatchingPotion');
|
expect(user._tmp.drop.type).to.eql('HatchingPotion');
|
||||||
expect(user._tmp.drop.value).to.eql(4);
|
expect(user._tmp.drop.value).to.eql(4);
|
||||||
@@ -129,9 +118,8 @@ describe('common.fns.randomDrop', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('drops an uncommon potion', () => {
|
it('drops an uncommon potion', () => {
|
||||||
predictableRandom = () => {
|
predictableRandom.returns(0.17);
|
||||||
return 0.17;
|
|
||||||
};
|
|
||||||
randomDrop(user, { task, predictableRandom });
|
randomDrop(user, { task, predictableRandom });
|
||||||
expect(user._tmp.drop.type).to.eql('HatchingPotion');
|
expect(user._tmp.drop.type).to.eql('HatchingPotion');
|
||||||
expect(user._tmp.drop.value).to.eql(3);
|
expect(user._tmp.drop.value).to.eql(3);
|
||||||
@@ -140,9 +128,8 @@ describe('common.fns.randomDrop', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('drops a common potion', () => {
|
it('drops a common potion', () => {
|
||||||
predictableRandom = () => {
|
predictableRandom.returns(0.20);
|
||||||
return 0.20;
|
|
||||||
};
|
|
||||||
randomDrop(user, { task, predictableRandom });
|
randomDrop(user, { task, predictableRandom });
|
||||||
expect(user._tmp.drop.type).to.eql('HatchingPotion');
|
expect(user._tmp.drop.type).to.eql('HatchingPotion');
|
||||||
expect(user._tmp.drop.value).to.eql(2);
|
expect(user._tmp.drop.value).to.eql(2);
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ import { daysSince } from '../cron';
|
|||||||
import { diminishingReturns } from '../statHelpers';
|
import { diminishingReturns } from '../statHelpers';
|
||||||
import randomVal from './randomVal';
|
import randomVal from './randomVal';
|
||||||
|
|
||||||
|
// TODO This is only used on the server
|
||||||
|
// move to user model as an instance method?
|
||||||
|
|
||||||
// Clone a drop object maintaining its functions so that we can change it without affecting the original item
|
// Clone a drop object maintaining its functions so that we can change it without affecting the original item
|
||||||
function cloneDropItem (drop) {
|
function cloneDropItem (drop) {
|
||||||
return _.cloneDeep(drop, (val) => {
|
return _.cloneDeep(drop, (val) => {
|
||||||
@@ -12,18 +15,20 @@ function cloneDropItem (drop) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function trueRandom () {
|
||||||
|
return Math.random();
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = function randomDrop (user, options, req = {}) {
|
module.exports = function randomDrop (user, options, req = {}) {
|
||||||
let acceptableDrops;
|
let acceptableDrops;
|
||||||
let chance;
|
|
||||||
let drop;
|
let drop;
|
||||||
let dropMultiplier;
|
let dropMultiplier;
|
||||||
let rarity;
|
let rarity;
|
||||||
let task;
|
|
||||||
|
|
||||||
let predictableRandom = options.predictableRandom || Math.random;
|
let predictableRandom = options.predictableRandom || trueRandom;
|
||||||
task = options.task;
|
let task = options.task;
|
||||||
|
|
||||||
chance = _.min([Math.abs(task.value - 21.27), 37.5]) / 150 + 0.02;
|
let chance = _.min([Math.abs(task.value - 21.27), 37.5]) / 150 + 0.02;
|
||||||
chance *= task.priority * // Task priority: +50% for Medium, +100% for Hard
|
chance *= task.priority * // Task priority: +50% for Medium, +100% for Hard
|
||||||
(1 + (task.streak / 100 || 0)) * // Streak bonus: +1% per streak
|
(1 + (task.streak / 100 || 0)) * // Streak bonus: +1% per streak
|
||||||
(1 + user._statsComputed.per / 100) * // PERception: +1% per point
|
(1 + user._statsComputed.per / 100) * // PERception: +1% per point
|
||||||
@@ -35,7 +40,7 @@ module.exports = function randomDrop (user, options, req = {}) {
|
|||||||
}, 0) || 0));
|
}, 0) || 0));
|
||||||
chance = diminishingReturns(chance, 0.75);
|
chance = diminishingReturns(chance, 0.75);
|
||||||
|
|
||||||
if (predictableRandom(user, user.stats.gp) < chance) {
|
if (predictableRandom() < chance) {
|
||||||
if (!user.party.quest.progress.collectedItems) user.party.quest.progress.collectedItems = 0;
|
if (!user.party.quest.progress.collectedItems) user.party.quest.progress.collectedItems = 0;
|
||||||
user.party.quest.progress.collectedItems++;
|
user.party.quest.progress.collectedItems++;
|
||||||
if (!user._tmp.quest) user._tmp.quest = {};
|
if (!user._tmp.quest) user._tmp.quest = {};
|
||||||
@@ -54,8 +59,8 @@ module.exports = function randomDrop (user, options, req = {}) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user.flags && user.flags.dropsEnabled && predictableRandom(user, user.stats.exp) < chance) {
|
if (user.flags && user.flags.dropsEnabled && predictableRandom() < chance) {
|
||||||
rarity = predictableRandom(user, user.stats.gp);
|
rarity = predictableRandom();
|
||||||
|
|
||||||
if (rarity > 0.6) { // food 40% chance
|
if (rarity > 0.6) { // food 40% chance
|
||||||
drop = cloneDropItem(randomVal(_.where(content.food, {
|
drop = cloneDropItem(randomVal(_.where(content.food, {
|
||||||
|
|||||||
Reference in New Issue
Block a user