From d5a354b499f90b5eca7e348b7f0a27541ba15637 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Thu, 23 Jun 2016 07:10:56 -0500 Subject: [PATCH] fix(api): Only award participating members the quest rewards (#7706) --- test/api/v3/unit/models/group.test.js | 212 +++++++++++++++++++++++++- website/server/models/group.js | 21 ++- 2 files changed, 225 insertions(+), 8 deletions(-) diff --git a/test/api/v3/unit/models/group.test.js b/test/api/v3/unit/models/group.test.js index f9cdbf3012..c3c7f615c1 100644 --- a/test/api/v3/unit/models/group.test.js +++ b/test/api/v3/unit/models/group.test.js @@ -385,18 +385,55 @@ describe('Group Model', () => { let quest = questScrolls[party.quest.key]; let finishQuest = sandbox.spy(Group.prototype, 'finishQuest'); - progress.collectedItems = 999; // TODO should this be collectedItems? What is this testing? + progress.collectedItems = 999; await Group.processQuestProgress(participatingMember, progress); expect(finishQuest).to.be.calledOnce; expect(finishQuest).to.be.calledWith(quest); }); + + it('gives out rewards when quest finishes', async () => { + progress.collectedItems = 999; + + await Group.processQuestProgress(participatingMember, progress); + + let [ + updatedLeader, + updatedParticipatingMember, + ] = await Promise.all([ + User.findById(questLeader._id), + User.findById(participatingMember._id), + ]); + + expect(updatedLeader.achievements.quests[party.quest.key]).to.eql(1); + expect(updatedLeader.stats.exp).to.be.greaterThan(0); + expect(updatedLeader.stats.gp).to.be.greaterThan(0); + expect(updatedParticipatingMember.achievements.quests[party.quest.key]).to.eql(1); + expect(updatedParticipatingMember.stats.exp).to.be.greaterThan(0); + expect(updatedParticipatingMember.stats.gp).to.be.greaterThan(0); + }); }); }); }); context('Instance Methods', () => { + describe('#getParticipatingQuestMembers', () => { + it('returns an array of members whose quest status set to true', () => { + party.quest.members = { + [participatingMember._id]: true, + [questLeader._id]: true, + [nonParticipatingMember._id]: false, + [undecidedMember._id]: null, + }; + + expect(party.getParticipatingQuestMembers()).to.eql([ + participatingMember._id, + questLeader._id, + ]); + }); + }); + describe('#sendChat', () => { beforeEach(() => { sandbox.spy(User, 'update'); @@ -795,5 +832,178 @@ describe('Group Model', () => { }); }); }); + + describe('#finishQuest', () => { + let quest; + + beforeEach(() => { + quest = questScrolls.whale; + party.quest.key = quest.key; + party.quest.active = false; + party.quest.leader = questLeader._id; + party.quest.members = { + [questLeader._id]: true, + [participatingMember._id]: true, + [nonParticipatingMember._id]: false, + [undecidedMember._id]: null, + }; + + sandbox.spy(User, 'update'); + }); + + it('gives out achievements', async () => { + await party.finishQuest(quest); + + let [ + updatedLeader, + updatedParticipatingMember, + ] = await Promise.all([ + User.findById(questLeader._id), + User.findById(participatingMember._id), + ]); + + expect(updatedLeader.achievements.quests[quest.key]).to.eql(1); + expect(updatedParticipatingMember.achievements.quests[quest.key]).to.eql(1); + }); + + it('gives xp and gold', async () => { + await party.finishQuest(quest); + + let [ + updatedLeader, + updatedParticipatingMember, + ] = await Promise.all([ + User.findById(questLeader._id), + User.findById(participatingMember._id), + ]); + + expect(updatedLeader.stats.exp).to.eql(quest.drop.exp); + expect(updatedLeader.stats.gp).to.eql(quest.drop.gp); + expect(updatedParticipatingMember.stats.exp).to.eql(quest.drop.exp); + expect(updatedParticipatingMember.stats.gp).to.eql(quest.drop.gp); + }); + + context('drops', () => { + it('awards gear', async () => { + let gearQuest = questScrolls.vice3; + + await party.finishQuest(gearQuest); + + let updatedParticipatingMember = await User.findById(participatingMember._id); + + expect(updatedParticipatingMember.items.gear.owned.weapon_special_2).to.eql(true); + }); + + it('awards eggs', async () => { + let eggQuest = questScrolls.vice3; + + await party.finishQuest(eggQuest); + + let updatedParticipatingMember = await User.findById(participatingMember._id); + + expect(updatedParticipatingMember.items.eggs.Dragon).to.eql(2); + }); + + it('awards food', async () => { + let foodQuest = questScrolls.moonstone3; + + await party.finishQuest(foodQuest); + + let updatedParticipatingMember = await User.findById(participatingMember._id); + + expect(updatedParticipatingMember.items.food.RottenMeat).to.eql(5); + }); + + it('awards hatching potions', async () => { + let hatchingPotionQuest = questScrolls.vice3; + + await party.finishQuest(hatchingPotionQuest); + + let updatedParticipatingMember = await User.findById(participatingMember._id); + + expect(updatedParticipatingMember.items.hatchingPotions.Shade).to.eql(2); + }); + + it('awards quests', async () => { + let questAwardQuest = questScrolls.vice2; + + await party.finishQuest(questAwardQuest); + + let updatedParticipatingMember = await User.findById(participatingMember._id); + + expect(updatedParticipatingMember.items.quests.vice3).to.eql(1); + }); + + it('awards pets', async () => { + let petQuest = questScrolls.evilsanta2; + + await party.finishQuest(petQuest); + + let updatedParticipatingMember = await User.findById(participatingMember._id); + + expect(updatedParticipatingMember.items.pets['BearCub-Polar']).to.eql(5); + }); + + it('awards mounts', async () => { + let mountQuest = questScrolls.evilsanta; + + await party.finishQuest(mountQuest); + + let updatedParticipatingMember = await User.findById(participatingMember._id); + + expect(updatedParticipatingMember.items.mounts['BearCub-Polar']).to.eql(true); + }); + }); + + context('Party quests', () => { + it('updates participating members with rewards', async () => { + await party.finishQuest(quest); + + expect(User.update).to.be.calledOnce; + expect(User.update).to.be.calledWithMatch({ + _id: { + $in: [questLeader._id, participatingMember._id], + }, + }); + }); + + it('sets user quest object to a clean state', async () => { + await party.finishQuest(quest); + + let updatedLeader = await User.findById(questLeader._id); + + expect(updatedLeader.party.quest.completed).to.eql('whale'); + expect(updatedLeader.party.quest.progress.up).to.eql(0); + expect(updatedLeader.party.quest.progress.down).to.eql(0); + expect(updatedLeader.party.quest.progress.collectedItems).to.eql(0); + expect(updatedLeader.party.quest.RSVPNeeded).to.eql(false); + }); + }); + + context('World quests in Tavern', () => { + let tavernQuest; + + beforeEach(() => { + party._id = TAVERN_ID; + party.quest.key = 'stressbeast'; + tavernQuest = questScrolls.stressbeast; + }); + + it('updates all users with rewards', async () => { + await party.finishQuest(tavernQuest); + + expect(User.update).to.be.calledOnce; + expect(User.update).to.be.calledWithMatch({}); + }); + + it('sets quest completed to the world quest key', async () => { + await party.finishQuest(tavernQuest); + + let updatedLeader = await User.findById(questLeader._id); + + expect(updatedLeader.party.quest.completed).to.eql(tavernQuest.key); + }); + }); + }); }); }); diff --git a/website/server/models/group.js b/website/server/models/group.js index c7c4ace84e..0a6e2f119c 100644 --- a/website/server/models/group.js +++ b/website/server/models/group.js @@ -248,6 +248,10 @@ schema.statics.toJSONCleanChat = function groupToJSONCleanChat (group, user) { return toJSON; }; +schema.methods.getParticipatingQuestMembers = function getParticipatingQuestMembers () { + return Object.keys(this.quest.members).filter(member => this.quest.members[member]); +}; + schema.methods.removeGroupInvitations = async function removeGroupInvitations () { let group = this; @@ -450,11 +454,14 @@ schema.statics.cleanGroupQuest = function cleanGroupQuest () { // Changes the group object update members schema.methods.finishQuest = async function finishQuest (quest) { let questK = quest.key; - let updates = {$inc: {}, $set: {}}; - - updates.$inc[`achievements.quests.${questK}`] = 1; - updates.$inc['stats.gp'] = Number(quest.drop.gp); - updates.$inc['stats.exp'] = Number(quest.drop.exp); + let updates = { + $inc: { + [`achievements.quests.${questK}`]: 1, + 'stats.gp': Number(quest.drop.gp), + 'stats.exp': Number(quest.drop.exp), + }, + $set: {}, + }; if (this._id === TAVERN_ID) { updates.$set['party.quest.completed'] = questK; // Just show the notif @@ -489,7 +496,7 @@ schema.methods.finishQuest = async function finishQuest (quest) { } }); - let q = this._id === TAVERN_ID ? {} : {_id: {$in: _.keys(this.quest.members)}}; + let q = this._id === TAVERN_ID ? {} : {_id: {$in: this.getParticipatingQuestMembers()}}; this.quest = {}; this.markModified('quest'); @@ -532,7 +539,7 @@ schema.methods._processBossQuest = async function processBossQuest (options) { // Everyone takes damage await User.update({ - _id: {$in: _.keys(_.pick(group.quest.members, _.identity))}, + _id: {$in: this.getParticipatingQuestMembers()}, }, { $inc: {'stats.hp': down}, }, {multi: true}).exec();