2013-08-31 21:47:03 +00:00
|
|
|
var mongoose = require("mongoose");
|
|
|
|
|
var Schema = mongoose.Schema;
|
2013-12-11 16:30:39 +00:00
|
|
|
var shared = require('habitrpg-shared');
|
2013-08-31 21:47:03 +00:00
|
|
|
var _ = require('lodash');
|
2013-12-20 22:43:10 +00:00
|
|
|
var async = require('async');
|
2013-08-29 05:45:19 +00:00
|
|
|
|
2013-08-31 21:47:03 +00:00
|
|
|
var GroupSchema = new Schema({
|
2013-12-11 16:30:39 +00:00
|
|
|
_id: {type: String, 'default': shared.uuid},
|
2013-08-29 05:45:19 +00:00
|
|
|
name: String,
|
|
|
|
|
description: String,
|
2013-10-28 05:27:07 +00:00
|
|
|
leader: {type: String, ref: 'User'},
|
|
|
|
|
members: [{type: String, ref: 'User'}],
|
|
|
|
|
invites: [{type: String, ref: 'User'}],
|
|
|
|
|
type: {type: String, "enum": ['guild', 'party']},
|
|
|
|
|
privacy: {type: String, "enum": ['private', 'public']},
|
2013-11-15 04:29:48 +00:00
|
|
|
//_v: {type: Number,'default': 0},
|
2013-08-29 05:45:19 +00:00
|
|
|
chat: Array,
|
|
|
|
|
/*
|
|
|
|
|
# [{
|
|
|
|
|
# timestamp: Date
|
|
|
|
|
# user: String
|
|
|
|
|
# text: String
|
|
|
|
|
# contributor: String
|
|
|
|
|
# uuid: String
|
|
|
|
|
# id: String
|
|
|
|
|
# }]
|
|
|
|
|
*/
|
|
|
|
|
|
2013-10-29 00:31:27 +00:00
|
|
|
memberCount: {type: Number, 'default': 0},
|
|
|
|
|
challengeCount: {type: Number, 'default': 0},
|
2013-08-29 05:45:19 +00:00
|
|
|
balance: Number,
|
|
|
|
|
logo: String,
|
2013-10-27 00:24:45 +00:00
|
|
|
leaderMessage: String,
|
2013-12-20 19:42:36 +00:00
|
|
|
challenges: [{type:'String', ref:'Challenge'}], // do we need this? could depend on back-ref instead (Challenge.find({group:GID}))
|
|
|
|
|
quest: {
|
|
|
|
|
key: String,
|
|
|
|
|
active: {type:Boolean, 'default':false},
|
2013-12-20 22:43:10 +00:00
|
|
|
progress:{
|
|
|
|
|
hp: Number,
|
|
|
|
|
collected: Schema.Types.Mixed,
|
|
|
|
|
},
|
2013-12-20 19:42:36 +00:00
|
|
|
|
2013-12-20 22:43:10 +00:00
|
|
|
//Shows boolean for each party-member who has accepted the quest. Eg {UUID: true, UUID: false}. Once all users click
|
|
|
|
|
//'Accept', the quest begins. If a false user waits too long, probably a good sign to prod them or boot them.
|
|
|
|
|
//TODO when booting user, remove from .joined and check again if we can now start the quest
|
2013-12-20 19:42:36 +00:00
|
|
|
members: Schema.Types.Mixed
|
|
|
|
|
}
|
2013-10-27 09:55:05 +00:00
|
|
|
}, {
|
2013-10-27 00:24:45 +00:00
|
|
|
strict: 'throw',
|
2013-10-27 09:55:43 +00:00
|
|
|
minimize: false // So empty objects are returned
|
2013-10-27 09:55:05 +00:00
|
|
|
});
|
2013-08-29 05:45:19 +00:00
|
|
|
|
2013-08-31 21:47:03 +00:00
|
|
|
/**
|
|
|
|
|
* Derby duplicated stuff. This is a temporary solution, once we're completely off derby we'll run an mongo migration
|
|
|
|
|
* to remove duplicates, then take these fucntions out
|
|
|
|
|
*/
|
|
|
|
|
function removeDuplicates(doc){
|
|
|
|
|
// Remove duplicate members
|
|
|
|
|
if (doc.members) {
|
|
|
|
|
var uniqMembers = _.uniq(doc.members);
|
|
|
|
|
if (uniqMembers.length != doc.members.length) {
|
|
|
|
|
doc.members = uniqMembers;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-30 03:37:22 +00:00
|
|
|
// FIXME this isn't always triggered, since we sometimes use update() or findByIdAndUpdate()
|
|
|
|
|
// @see https://github.com/LearnBoost/mongoose/issues/964
|
2013-08-31 21:47:03 +00:00
|
|
|
GroupSchema.pre('save', function(next){
|
|
|
|
|
removeDuplicates(this);
|
2013-10-29 00:31:27 +00:00
|
|
|
this.memberCount = _.size(this.members);
|
|
|
|
|
this.challengeCount = _.size(this.challenges);
|
2013-08-31 21:47:03 +00:00
|
|
|
next();
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
GroupSchema.methods.toJSON = function(){
|
|
|
|
|
var doc = this.toObject();
|
|
|
|
|
removeDuplicates(doc);
|
2013-10-29 19:26:13 +00:00
|
|
|
doc._isMember = this._isMember;
|
2013-10-30 03:37:22 +00:00
|
|
|
|
|
|
|
|
// @see pre('save') comment above
|
|
|
|
|
this.memberCount = _.size(this.members);
|
|
|
|
|
this.challengeCount = _.size(this.challenges);
|
|
|
|
|
|
2013-08-31 21:47:03 +00:00
|
|
|
return doc;
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-20 22:43:10 +00:00
|
|
|
GroupSchema.methods.sendChat = function(message, user){
|
|
|
|
|
var group = this;
|
|
|
|
|
var message = {
|
|
|
|
|
id: shared.uuid(),
|
|
|
|
|
text: message,
|
|
|
|
|
timestamp: +(new Date)
|
|
|
|
|
};
|
|
|
|
|
if (user) {
|
|
|
|
|
_.defaults(message, {
|
|
|
|
|
uuid: user._id,
|
|
|
|
|
contributor: user.contributor && user.contributor.toObject(),
|
|
|
|
|
backer: user.backer && user.backer.toObject(),
|
|
|
|
|
user: user.profile.name,
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
message.uuid = 'system';
|
|
|
|
|
}
|
|
|
|
|
group.chat.unshift(message);
|
|
|
|
|
group.chat.splice(200);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GroupSchema.methods.hurtBoss = function(delta, cb) {
|
|
|
|
|
var group = this;
|
|
|
|
|
group.quest.progress.hp -= delta;
|
|
|
|
|
var hp = group.quest.progress.hp;
|
|
|
|
|
if (group.quest.progress.hp <= 0) {
|
|
|
|
|
var key = group.quest.key,
|
|
|
|
|
quest = shared.content.quests[key];
|
|
|
|
|
|
|
|
|
|
var parallel = _.reduce(group.members, function(m,v,k){
|
|
|
|
|
|
|
|
|
|
// Achievement
|
|
|
|
|
_.defaults(v.achievements, {quests:{}})
|
|
|
|
|
if (!v.achievements.quests[key]) v.achievements.quests[key] = 0;
|
|
|
|
|
v.achievements.quests[key]++;
|
|
|
|
|
v.markModified('achievements');
|
|
|
|
|
|
|
|
|
|
// Drops
|
|
|
|
|
v.stats.gp += +quest.drop.gp;
|
|
|
|
|
v.stats.exp += +quest.drop.exp;
|
|
|
|
|
switch (quest.drop.type) {
|
|
|
|
|
case 'gear':
|
|
|
|
|
// TODO This means they can lose their new gear on death, is that what we want?
|
|
|
|
|
v.items.gear.owned[quest.drop.key] = true;
|
|
|
|
|
break;
|
|
|
|
|
case 'eggs':
|
|
|
|
|
case 'food':
|
|
|
|
|
case 'hatchingPotions':
|
|
|
|
|
if (!v.items.hatchingPotions[quest.drop.key]) v.items.hatchingPotions[quest.drop.key] = 0;
|
|
|
|
|
v.items.hatchingPotions[quest.drop.key]++;
|
|
|
|
|
break;
|
|
|
|
|
case 'pets':
|
|
|
|
|
if (!v.items.pets[quest.drop.key]) v.items.pets[quest.drop.key] = 5;
|
|
|
|
|
break;
|
|
|
|
|
case 'mounts':
|
|
|
|
|
v.items.mounts[quest.drop.key] = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
v.party.quest.key = undefined;
|
|
|
|
|
v.party.quest.collection = {};
|
|
|
|
|
v.markModified('party.quest');
|
|
|
|
|
|
|
|
|
|
v._v++;
|
|
|
|
|
m.push(function(cb3){ v.save(cb3); })
|
|
|
|
|
return m;
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
// Finish the quest
|
|
|
|
|
group.quest = {};group.markModified('quest');
|
|
|
|
|
group.sendChat('`' + quest.name + ' has been slain! Party has received their rewards`');
|
|
|
|
|
|
|
|
|
|
parallel.push(function(cb3){
|
|
|
|
|
group.save(cb3);
|
|
|
|
|
})
|
|
|
|
|
async.parallel(parallel,cb);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
group.save(cb);
|
|
|
|
|
}
|
|
|
|
|
return hp;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-31 21:47:03 +00:00
|
|
|
module.exports.schema = GroupSchema;
|
2013-11-14 04:20:33 +00:00
|
|
|
module.exports.model = mongoose.model("Group", GroupSchema);
|