mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-12-18 11:32:25 -05:00
96 lines
4.7 KiB
CoffeeScript
96 lines
4.7 KiB
CoffeeScript
mongoose = require 'mongoose'
|
|
jsonschema = require '../../app/schemas/models/earned_achievement'
|
|
util = require '../../app/core/utils'
|
|
log = require 'winston'
|
|
|
|
EarnedAchievementSchema = new mongoose.Schema({
|
|
notified:
|
|
type: Boolean
|
|
default: false
|
|
}, {strict:false})
|
|
|
|
EarnedAchievementSchema.pre 'save', (next) ->
|
|
@set('changed', new Date())
|
|
next()
|
|
|
|
EarnedAchievementSchema.index({user: 1, achievement: 1}, {unique: true, name: 'earned achievement index'})
|
|
EarnedAchievementSchema.index({user: 1, changed: -1}, {name: 'latest '})
|
|
|
|
EarnedAchievementSchema.statics.createForAchievement = (achievement, doc, originalDocObj=null, previouslyEarnedAchievement=null, done) ->
|
|
User = require '../users/User'
|
|
userObjectID = doc.get(achievement.get('userField'))
|
|
userID = if _.isObject userObjectID then userObjectID.toHexString() else userObjectID # Standardize! Use strings, not ObjectId's
|
|
|
|
earned =
|
|
user: userID
|
|
achievement: achievement._id.toHexString()
|
|
achievementName: achievement.get 'name'
|
|
earnedRewards: achievement.get 'rewards'
|
|
|
|
pointWorth = achievement.get('worth') ? 10
|
|
gemWorth = achievement.get('rewards')?.gems ? 0
|
|
earnedPoints = 0
|
|
earnedGems = 0
|
|
|
|
wrapUp = (earnedAchievementDoc) ->
|
|
# Update user's experience points
|
|
update = {$inc: {points: earnedPoints, 'earned.gems': earnedGems}}
|
|
for rewardType, rewards of achievement.get('rewards') ? {}
|
|
continue if rewardType is 'gems'
|
|
if rewards.length
|
|
update.$addToSet ?= {}
|
|
update.$addToSet["earned.#{rewardType}"] = $each: rewards
|
|
User.update {_id: mongoose.Types.ObjectId(userID)}, update, {}, (err, result) ->
|
|
log.error err if err?
|
|
done?(earnedAchievementDoc)
|
|
|
|
isRepeatable = achievement.get('proportionalTo')?
|
|
if isRepeatable
|
|
#log.debug 'Upserting repeatable achievement called \'' + (achievement.get 'name') + '\' for ' + userID
|
|
proportionalTo = achievement.get 'proportionalTo'
|
|
docObj = doc.toObject()
|
|
newAmount = util.getByPath(docObj, proportionalTo) or 0
|
|
updateEarnedAchievement = (originalAmount) ->
|
|
#console.log 'original amount is', originalAmount, 'and new amount is', newAmount, 'for', proportionalTo, 'with doc', docObj, 'and previously earned achievement amount', previouslyEarnedAchievement?.get('achievedAmount'), 'because we had originalDocObj', originalDocObj
|
|
|
|
if originalAmount isnt newAmount
|
|
expFunction = achievement.getExpFunction()
|
|
earned.notified = false
|
|
earned.achievedAmount = newAmount
|
|
#console.log 'earnedPoints is', (expFunction(newAmount) - expFunction(originalAmount)) * pointWorth, 'was', earned.earnedPoints, earned.previouslyAchievedAmount, 'got exp function for new amount', newAmount, expFunction(newAmount), 'for original amount', originalAmount, expFunction(originalAmount), 'with point worth', pointWorth
|
|
earnedPoints = earned.earnedPoints = (expFunction(newAmount) - expFunction(originalAmount)) * pointWorth
|
|
earnedGems = earned.earnedGems = (expFunction(newAmount) - expFunction(originalAmount)) * gemWorth
|
|
earned.previouslyAchievedAmount = originalAmount
|
|
EarnedAchievement.update {achievement: earned.achievement, user: earned.user}, earned, {upsert: true}, (err) ->
|
|
return log.error err if err?
|
|
|
|
wrapUp(new EarnedAchievement(earned))
|
|
else
|
|
done?()
|
|
|
|
if proportionalTo is 'simulatedBy' and newAmount > 0 and not previouslyEarnedAchievement and Math.random() < 0.1
|
|
# Because things like simulatedBy get updated with $inc and not the post-save plugin hook,
|
|
# we (infrequently) fetch the previously earned achievement so we can really update.
|
|
EarnedAchievement.findOne {user: earned.user, achievement: earned.achievement}, (err, previouslyEarnedAchievement) ->
|
|
log.error err if err?
|
|
updateEarnedAchievement previouslyEarnedAchievement?.get('achievedAmount') or 0
|
|
else if previouslyEarnedAchievement
|
|
updateEarnedAchievement previouslyEarnedAchievement.get('achievedAmount') or 0
|
|
else if originalDocObj # This branch could get buggy if unchangedCopy tracking isn't working.
|
|
updateEarnedAchievement util.getByPath(originalDocObj, proportionalTo) or 0
|
|
else
|
|
updateEarnedAchievement 0
|
|
|
|
else # not alreadyAchieved
|
|
#log.debug 'Creating a new earned achievement called \'' + (achievement.get 'name') + '\' for ' + userID
|
|
earned.earnedPoints = pointWorth
|
|
earned.earnedGems = gemWorth
|
|
(new EarnedAchievement(earned)).save (err, doc) ->
|
|
return log.error err if err?
|
|
earnedPoints = pointWorth
|
|
earnedGems = gemWorth
|
|
wrapUp(doc)
|
|
|
|
User.saveActiveUser userID, "achievement"
|
|
|
|
module.exports = EarnedAchievement = mongoose.model('EarnedAchievement', EarnedAchievementSchema)
|