mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-17 06:37:23 +01:00
fix: Change quest collection to calculate items on the server only
This commit is contained in:
@@ -17,9 +17,7 @@ module.exports = function randomDrop (user, options, req = {}) {
|
|||||||
let acceptableDrops;
|
let acceptableDrops;
|
||||||
let chance;
|
let chance;
|
||||||
let drop;
|
let drop;
|
||||||
let dropK;
|
|
||||||
let dropMultiplier;
|
let dropMultiplier;
|
||||||
let quest;
|
|
||||||
let rarity;
|
let rarity;
|
||||||
let task;
|
let task;
|
||||||
|
|
||||||
@@ -38,15 +36,8 @@ module.exports = function randomDrop (user, options, req = {}) {
|
|||||||
}, 0) || 0));
|
}, 0) || 0));
|
||||||
chance = diminishingReturns(chance, 0.75);
|
chance = diminishingReturns(chance, 0.75);
|
||||||
|
|
||||||
if (user.party.quest.key)
|
if (predictableRandom(user, user.stats.gp) < chance) {
|
||||||
quest = content.quests[user.party.quest.key];
|
user.party.quest.progress.collect++;
|
||||||
if (quest && quest.collect && predictableRandom(user, user.stats.gp) < chance) {
|
|
||||||
dropK = randomVal(user, quest.collect, {
|
|
||||||
key: true,
|
|
||||||
});
|
|
||||||
if (!user.party.quest.progress.collect[dropK])
|
|
||||||
user.party.quest.progress.collect[dropK] = 0;
|
|
||||||
user.party.quest.progress.collect[dropK]++;
|
|
||||||
user.markModified('party.quest.progress');
|
user.markModified('party.quest.progress');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,10 +44,7 @@ describe('POST /debug/quest-progress', () => {
|
|||||||
|
|
||||||
await user.sync();
|
await user.sync();
|
||||||
|
|
||||||
expect(user.party.quest.progress.collect).to.eql({
|
expect(user.party.quest.progress.collect).to.eql(300);
|
||||||
tracks: 300,
|
|
||||||
branches: 300,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns error when not in production mode', async () => {
|
it('returns error when not in production mode', async () => {
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ describe('POST /groups/:groupId/quests/abort', () => {
|
|||||||
progress: {
|
progress: {
|
||||||
up: 0,
|
up: 0,
|
||||||
down: 0,
|
down: 0,
|
||||||
collect: {},
|
collect: 0,
|
||||||
},
|
},
|
||||||
completed: null,
|
completed: null,
|
||||||
RSVPNeeded: false,
|
RSVPNeeded: false,
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ describe('POST /groups/:groupId/quests/cancel', () => {
|
|||||||
progress: {
|
progress: {
|
||||||
up: 0,
|
up: 0,
|
||||||
down: 0,
|
down: 0,
|
||||||
collect: {},
|
collect: 0,
|
||||||
},
|
},
|
||||||
completed: null,
|
completed: null,
|
||||||
RSVPNeeded: false,
|
RSVPNeeded: false,
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ describe('POST /groups/:groupId/quests/leave', () => {
|
|||||||
progress: {
|
progress: {
|
||||||
up: 0,
|
up: 0,
|
||||||
down: 0,
|
down: 0,
|
||||||
collect: {},
|
collect: 0,
|
||||||
},
|
},
|
||||||
completed: null,
|
completed: null,
|
||||||
RSVPNeeded: false,
|
RSVPNeeded: false,
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ describe('POST /groups/:groupId/quests/reject', () => {
|
|||||||
progress: {
|
progress: {
|
||||||
up: 0,
|
up: 0,
|
||||||
down: 0,
|
down: 0,
|
||||||
collect: {},
|
collect: 0,
|
||||||
},
|
},
|
||||||
completed: null,
|
completed: null,
|
||||||
RSVPNeeded: false,
|
RSVPNeeded: false,
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ describe('Group Model', () => {
|
|||||||
|
|
||||||
expect(participatingMember.party.quest.key).to.eql('whale');
|
expect(participatingMember.party.quest.key).to.eql('whale');
|
||||||
expect(participatingMember.party.quest.progress.down).to.eql(0);
|
expect(participatingMember.party.quest.progress.down).to.eql(0);
|
||||||
expect(participatingMember.party.quest.progress.collect).to.eql({});
|
expect(participatingMember.party.quest.progress.collect).to.eql(0);
|
||||||
expect(participatingMember.party.quest.completed).to.eql(null);
|
expect(participatingMember.party.quest.completed).to.eql(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -158,12 +158,12 @@ describe('Group Model', () => {
|
|||||||
|
|
||||||
expect(participatingMember.party.quest.key).to.eql('whale');
|
expect(participatingMember.party.quest.key).to.eql('whale');
|
||||||
expect(participatingMember.party.quest.progress.down).to.eql(0);
|
expect(participatingMember.party.quest.progress.down).to.eql(0);
|
||||||
expect(participatingMember.party.quest.progress.collect).to.eql({});
|
expect(participatingMember.party.quest.progress.collect).to.eql(0);
|
||||||
expect(participatingMember.party.quest.completed).to.eql(null);
|
expect(participatingMember.party.quest.completed).to.eql(null);
|
||||||
|
|
||||||
expect(questLeader.party.quest.key).to.eql('whale');
|
expect(questLeader.party.quest.key).to.eql('whale');
|
||||||
expect(questLeader.party.quest.progress.down).to.eql(0);
|
expect(questLeader.party.quest.progress.down).to.eql(0);
|
||||||
expect(questLeader.party.quest.progress.collect).to.eql({});
|
expect(questLeader.party.quest.progress.collect).to.eql(0);
|
||||||
expect(questLeader.party.quest.completed).to.eql(null);
|
expect(questLeader.party.quest.completed).to.eql(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -255,7 +255,6 @@ describe('Group Model', () => {
|
|||||||
$set: {
|
$set: {
|
||||||
'party.quest.key': 'whale',
|
'party.quest.key': 'whale',
|
||||||
'party.quest.progress.down': 0,
|
'party.quest.progress.down': 0,
|
||||||
'party.quest.progress.collect': {},
|
|
||||||
'party.quest.completed': null,
|
'party.quest.completed': null,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -284,7 +283,7 @@ describe('Group Model', () => {
|
|||||||
|
|
||||||
expect(userQuest.key).to.eql('whale');
|
expect(userQuest.key).to.eql('whale');
|
||||||
expect(userQuest.progress.down).to.eql(0);
|
expect(userQuest.progress.down).to.eql(0);
|
||||||
expect(userQuest.progress.collect).to.eql({});
|
expect(userQuest.progress.collect).to.eql(0);
|
||||||
expect(userQuest.completed).to.eql(null);
|
expect(userQuest.completed).to.eql(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -554,9 +553,7 @@ describe('Group Model', () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
progress = {
|
progress = {
|
||||||
collect: {
|
collect: 5,
|
||||||
soapBars: 5,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
quest = questScrolls.atom1;
|
quest = questScrolls.atom1;
|
||||||
|
|
||||||
@@ -582,7 +579,7 @@ describe('Group Model', () => {
|
|||||||
group: party,
|
group: party,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(party.quest.progress.collect.soapBars).to.eq(5)
|
expect(party.quest.progress.collect.soapBars).to.eq(5);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sends a chat message about progress', async () => {
|
it('sends a chat message about progress', async () => {
|
||||||
@@ -598,7 +595,7 @@ describe('Group Model', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('sends a chat message if no progress is made', async () => {
|
it('sends a chat message if no progress is made', async () => {
|
||||||
delete progress.collect.soapBars;
|
progress.collect = 0;
|
||||||
|
|
||||||
await Group.processCollectionQuest({
|
await Group.processCollectionQuest({
|
||||||
user: participatingMember,
|
user: participatingMember,
|
||||||
@@ -612,7 +609,7 @@ describe('Group Model', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('sends message about victory', async () => {
|
it('sends message about victory', async () => {
|
||||||
progress.collect.soapBars = 500;
|
progress.collect = 500;
|
||||||
|
|
||||||
await Group.processCollectionQuest({
|
await Group.processCollectionQuest({
|
||||||
user: participatingMember,
|
user: participatingMember,
|
||||||
@@ -626,7 +623,7 @@ describe('Group Model', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('calls finishQuest when all items are found', async () => {
|
it('calls finishQuest when all items are found', async () => {
|
||||||
progress.collect.soapBars = 999;
|
progress.collect = 999;
|
||||||
sandbox.spy(party, 'finishQuest');
|
sandbox.spy(party, 'finishQuest');
|
||||||
|
|
||||||
await Group.processCollectionQuest({
|
await Group.processCollectionQuest({
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import {
|
|||||||
generateDaily,
|
generateDaily,
|
||||||
generateReward,
|
generateReward,
|
||||||
} from '../../helpers/common.helper';
|
} from '../../helpers/common.helper';
|
||||||
import content from '../../../common/script/content/index';
|
|
||||||
|
|
||||||
describe('common.fns.randomDrop', () => {
|
describe('common.fns.randomDrop', () => {
|
||||||
let user;
|
let user;
|
||||||
@@ -22,23 +21,16 @@ describe('common.fns.randomDrop', () => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* function signature as follows:
|
|
||||||
* randomDrop(user, modifiers) {}
|
|
||||||
* modifiers = { task, delta = null }
|
|
||||||
**/
|
|
||||||
|
|
||||||
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.collect).to.eql({});
|
expect(user.party.quest.progress.collect).to.eql(0);
|
||||||
user.party.quest.key = 'vice2';
|
user.party.quest.key = 'vice2';
|
||||||
let collectWhat = Object.keys(content.quests[user.party.quest.key].collect)[0]; // lightCrystal
|
|
||||||
predictableRandom = () => {
|
predictableRandom = () => {
|
||||||
return 0.0001;
|
return 0.0001;
|
||||||
};
|
};
|
||||||
randomDrop(user, { task, predictableRandom });
|
randomDrop(user, { task, predictableRandom });
|
||||||
expect(user.party.quest.progress.collect[collectWhat]).to.eql(1);
|
expect(user.party.quest.progress.collect).to.eql(1);
|
||||||
randomDrop(user, { task, predictableRandom });
|
randomDrop(user, { task, predictableRandom });
|
||||||
expect(user.party.quest.progress.collect[collectWhat]).to.eql(2);
|
expect(user.party.quest.progress.collect).to.eql(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
context('drops enabled', () => {
|
context('drops enabled', () => {
|
||||||
|
|||||||
@@ -380,7 +380,7 @@ describe('Groups Controller', function() {
|
|||||||
expect(user.party.quest.progress).to.eql({
|
expect(user.party.quest.progress).to.eql({
|
||||||
up: 0,
|
up: 0,
|
||||||
down: 0,
|
down: 0,
|
||||||
collect: {}
|
collect: 0,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -171,11 +171,7 @@ api.questProgress = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (quest.collect) {
|
if (quest.collect) {
|
||||||
let collect = user.party.quest.progress.collect;
|
user.party.quest.progress.collect += 300;
|
||||||
_.each(quest.collect, (details, item) => {
|
|
||||||
collect[item] = collect[item] || 0;
|
|
||||||
collect[item] += 300;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
user.markModified('party.quest.progress');
|
user.markModified('party.quest.progress');
|
||||||
|
|||||||
@@ -277,8 +277,7 @@ export function cron (options = {}) {
|
|||||||
// After all is said and done, progress up user's effect on quest, return those values & reset the user's
|
// After all is said and done, progress up user's effect on quest, return those values & reset the user's
|
||||||
let progress = user.party.quest.progress;
|
let progress = user.party.quest.progress;
|
||||||
let _progress = _.cloneDeep(progress);
|
let _progress = _.cloneDeep(progress);
|
||||||
_.merge(progress, {down: 0, up: 0});
|
_.merge(progress, {down: 0, up: 0, collect: 0});
|
||||||
progress.collect = _.transform(progress.collect, (m, v, k) => m[k] = 0);
|
|
||||||
|
|
||||||
// TODO: Clean PMs - keep 200 for subscribers and 50 for free users. Should also be done while resting in the inn
|
// TODO: Clean PMs - keep 200 for subscribers and 50 for free users. Should also be done while resting in the inn
|
||||||
// let numberOfPMs = Object.keys(user.inbox.messages).length;
|
// let numberOfPMs = Object.keys(user.inbox.messages).length;
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ function _cleanQuestProgress (merge) {
|
|||||||
progress: {
|
progress: {
|
||||||
up: 0,
|
up: 0,
|
||||||
down: 0,
|
down: 0,
|
||||||
collect: {},
|
collect: 0,
|
||||||
},
|
},
|
||||||
completed: null,
|
completed: null,
|
||||||
RSVPNeeded: false,
|
RSVPNeeded: false,
|
||||||
@@ -365,7 +365,6 @@ schema.methods.startQuest = async function startQuest (user) {
|
|||||||
if (userIsParticipating) {
|
if (userIsParticipating) {
|
||||||
user.party.quest.key = this.quest.key;
|
user.party.quest.key = this.quest.key;
|
||||||
user.party.quest.progress.down = 0;
|
user.party.quest.progress.down = 0;
|
||||||
user.party.quest.progress.collect = collected;
|
|
||||||
user.party.quest.completed = null;
|
user.party.quest.completed = null;
|
||||||
user.markModified('party.quest');
|
user.markModified('party.quest');
|
||||||
}
|
}
|
||||||
@@ -389,7 +388,6 @@ schema.methods.startQuest = async function startQuest (user) {
|
|||||||
$set: {
|
$set: {
|
||||||
'party.quest.key': this.quest.key,
|
'party.quest.key': this.quest.key,
|
||||||
'party.quest.progress.down': 0,
|
'party.quest.progress.down': 0,
|
||||||
'party.quest.progress.collect': collected,
|
|
||||||
'party.quest.completed': null,
|
'party.quest.completed': null,
|
||||||
},
|
},
|
||||||
}, { multi: true }).exec();
|
}, { multi: true }).exec();
|
||||||
@@ -499,11 +497,18 @@ async function processCollectionQuest (options) {
|
|||||||
group,
|
group,
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
_.each(progress.collect, (v, k) => {
|
let itemsFound = {};
|
||||||
group.quest.progress.collect[k] += v;
|
|
||||||
|
_.times(progress.collect, () => {
|
||||||
|
let item = shared.fns.randomVal(user, quest.collect, {key: true});
|
||||||
|
if (!itemsFound[item]) {
|
||||||
|
itemsFound[item] = 0;
|
||||||
|
}
|
||||||
|
itemsFound[item]++;
|
||||||
|
group.quest.progress.collect[item]++;
|
||||||
});
|
});
|
||||||
|
|
||||||
let foundText = _.reduce(progress.collect, (m, v, k) => {
|
let foundText = _.reduce(itemsFound, (m, v, k) => {
|
||||||
m.push(`${v} ${quest.collect[k].text('en')}`);
|
m.push(`${v} ${quest.collect[k].text('en')}`);
|
||||||
return m;
|
return m;
|
||||||
}, []);
|
}, []);
|
||||||
|
|||||||
@@ -376,9 +376,7 @@ export let schema = new Schema({
|
|||||||
progress: {
|
progress: {
|
||||||
up: {type: Number, default: 0},
|
up: {type: Number, default: 0},
|
||||||
down: {type: Number, default: 0},
|
down: {type: Number, default: 0},
|
||||||
collect: {type: Schema.Types.Mixed, default: () => {
|
collect: {type: Number, default: 0},
|
||||||
return {};
|
|
||||||
}}, // {feather:1, ingot:2}
|
|
||||||
},
|
},
|
||||||
completed: String, // When quest is done, we move it from key => completed, and it's a one-time flag (for modal) that they unset by clicking "ok" in browser
|
completed: String, // When quest is done, we move it from key => completed, and it's a one-time flag (for modal) that they unset by clicking "ok" in browser
|
||||||
RSVPNeeded: {type: Boolean, default: false}, // Set to true when invite is pending, set to false when quest invite is accepted or rejected, quest starts, or quest is cancelled
|
RSVPNeeded: {type: Boolean, default: false}, // Set to true when invite is pending, set to false when quest invite is accepted or rejected, quest starts, or quest is cancelled
|
||||||
|
|||||||
Reference in New Issue
Block a user