diff --git a/package.json b/package.json index fd5f3a31de..f60ceb65d5 100644 --- a/package.json +++ b/package.json @@ -16,9 +16,7 @@ "guid": "*", "moment": "*", "stripe": "*", - "lodash": "1.0.x", "coffee-script": "1.4.x", - "underscore": "*", "mongoskin": "*", "nconf": "*", "icalendar": "git://github.com/lefnire/node-icalendar#master", @@ -26,7 +24,8 @@ "resolve": "~0.2.3", "expect.js": "~0.2.0", "derby-i18n": "git://github.com/switz/derby-i18n#master", - "relative-date": "~1.1.1" + "relative-date": "~1.1.1", + "lodash": "~1.2.1" }, "private": true, "subdomain": "habitrpg", diff --git a/src/app/algos.coffee b/src/app/algos.coffee deleted file mode 100644 index 1e9ab67cdf..0000000000 --- a/src/app/algos.coffee +++ /dev/null @@ -1,74 +0,0 @@ -XP = 15 -HP = 2 - -priorityValue = module.exports.priorityValue = (priority='!') -> - switch priority - when '!' then 1 - when '!!' then 1.5 - when '!!!' then 2 - else 1 - -module.exports.tnl = (level) -> - if level >= 100 - value = 0 - else - value = Math.round(((Math.pow(level,2)*0.25)+(10 * level) + 139.75)/10)*10 # round to nearest 10 - return value - -### - Calculates Exp modificaiton based on level and weapon strength - {value} task.value for exp gain - {weaponStrength) weapon strength - {level} current user level - {priority} user-defined priority multiplier -### -module.exports.expModifier = (value, weaponStr, level, priority='!') -> - str = (level-1) / 2 # ultimately get this from user - totalStr = (str + weaponStr) / 100 - strMod = 1 + totalStr - exp = value * XP * strMod * priorityValue(priority) - return Math.round(exp) - -### - Calculates HP modification based on level and armor defence - {value} task.value for hp loss - {armorDefense} defense from armor - {helmDefense} defense from helm - {level} current user level - {priority} user-defined priority multiplier -### -module.exports.hpModifier = (value, armorDef, helmDef, shieldDef, level, priority='!') -> - def = (level-1) / 2 # ultimately get this from user? - totalDef = (def + armorDef + helmDef + shieldDef) / 100 #ultimate get this from user - defMod = 1 - totalDef - hp = value * HP * defMod * priorityValue(priority) - return Math.round(hp * 10)/10 # round to 1dp - -### - Future use - {priority} user-defined priority multiplier -### -module.exports.gpModifier = (value, modifier, priority='!', streak, model) -> - val = value * modifier * priorityValue(priority) - if streak and model - streakBonus = streak / 100 + 1 # eg, 1-day streak is 1.1, 2-day is 1.2, etc - afterStreak = val * streakBonus - model.set('_streakBonus', afterStreak - val) if (val > 0) # can we do this without model? just global emit? - return afterStreak - else - return val - -### - Calculates the next task.value based on direction - Uses a capped inverse log y=.95^x, y>= -5 - {currentValue} the current value of the task - {direction} up or down -### -module.exports.taskDeltaFormula = (currentValue, direction) -> - if currentValue < -47.27 then currentValue = -47.27 - else if currentValue > 21.27 then currentValue = 21.27 - delta = Math.pow(0.9747,currentValue) - return delta if direction is 'up' - return -delta - - diff --git a/src/app/character.coffee b/src/app/character.coffee index 15b7563625..87159d2b56 100644 --- a/src/app/character.coffee +++ b/src/app/character.coffee @@ -1,6 +1,6 @@ browser = require './browser' items = require './items' -algos = require './algos' +algos = require 'habitrpg-shared/script/algos' moment = require 'moment' _ = require 'underscore' @@ -22,7 +22,6 @@ module.exports.app = (appExports, model) -> owned = user.get('items') # unless they're already at 0-everything if parseInt(owned.armor)>0 or parseInt(owned.head)>0 or parseInt(owned.shield)>0 or parseInt(owned.weapon)>0 - console.log 'test' # find a random item to lose until loseThisItem #candidate = {0:'items.armor', 1:'items.head', 2:'items.shield', 3:'items.weapon', 4:'stats.gp'}[Math.random()*5|0] diff --git a/src/app/debug.coffee b/src/app/debug.coffee index a11541a5fc..32a1b82589 100644 --- a/src/app/debug.coffee +++ b/src/app/debug.coffee @@ -1,5 +1,5 @@ moment = require 'moment' -algos = require './algos' +algos = require 'habitrpg-shared/script/algos' module.exports.app = (appExports, model) -> user = model.at('_user') diff --git a/src/app/index.coffee b/src/app/index.coffee index 6ff0c4e920..a3c1275b4a 100644 --- a/src/app/index.coffee +++ b/src/app/index.coffee @@ -117,7 +117,7 @@ ready (model) -> user = model.at('_user') model.setNull '_user.apiToken', derby.uuid() - require('./scoring').cron(model) + #FIXME require('habitrpg-shared/script/algos').cron(user) require('./character').app(exports, model) require('./tasks').app(exports, model) diff --git a/src/app/tasks.coffee b/src/app/tasks.coffee index 50d5c273c5..44a237dd20 100644 --- a/src/app/tasks.coffee +++ b/src/app/tasks.coffee @@ -1,12 +1,35 @@ -scoring = require './scoring' +algos = require 'habitrpg-shared/script/algos' helpers = require 'habitrpg-shared/script/helpers' -_ = require 'underscore' +_ = require 'lodash' moment = require 'moment' -character = require './character' + +### + Make scoring functionality available to the app +### module.exports.app = (appExports, model) -> + character = require './character' user = model.at('_user') + ### + algos.score wrapper for habitrpg-helpers to work in Derby. We need to do model.set() instead of simply setting the + object properties, and it's very difficult to diff the two objects and find dot-separated paths to set. So we to first + clone our user object (if we don't do that, it screws with model.on() listeners, ping Tyler for an explaination), + perform the updates while tracking paths, then all the values at those paths + ### + score = (user, taskId, direction) -> + uObj = _.cloneDeep user.get() # need to clone, else derby won't catch model.set()'s after obj property sets + tObj = uObj.tasks[taskId] + + # Stuff for undo + tObjBefore = _.cloneDeep tObj + tObjBefore.completed = !tObjBefore.completed if tObj.type in ['daily', 'todo'] + setUndo uObj.stats, tObjBefore # set previous state for undo + + paths = {} + algos.score(uObj, tObj, direction, {paths:paths}) + _.each paths, (v,k) -> user.set(k,helpers.dotGet(k, uObj)) + appExports.addTask = (e, el) -> type = $(el).attr('data-task-type') newModel = model.at('_new' + type.charAt(0).toUpperCase() + type.slice(1)) @@ -28,26 +51,24 @@ module.exports.app = (appExports, model) -> model.unshift "_#{type}List", newTask newModel.set '' - appExports.del = (e, el) -> + appExports.del = (e) -> # Derby extends model.at to support creation from DOM nodes task = e.at() id = task.get('id') history = task.get('history') - if history and history.length>2 + if history and history.length > 2 # prevent delete-and-recreate hack on red tasks if task.get('value') < 0 - result = confirm("Are you sure? Deleting this task will hurt you (to prevent deleting, then re-creating red tasks).") - if result != true - return # Cancel. Don't delete, don't hurt user - else + if confirm("Are you sure? Deleting this task will hurt you (to prevent deleting, then re-creating red tasks).") is true task.set('type','habit') # hack to make sure it hits HP, instead of performing "undo checkbox" - scoring.score(model, id, direction:'down') + score(user, id, 'down') + else + return # Cancel. Don't delete, don't hurt user # prevent accidently deleting long-standing tasks else - result = confirm("Are you sure you want to delete this task?") - return if result != true + return unless confirm("Are you sure you want to delete this task?") is true #TODO bug where I have to delete from _users.tasks AND _{type}List, # fix when query subscriptions implemented properly @@ -113,14 +134,9 @@ module.exports.app = (appExports, model) -> Call scoring functions for habits & rewards (todos & dailies handled below) ### appExports.score = (e, el) -> - task= model.at $(el).parents('li')[0] - taskObj = task.get() + task = model.at $(el).parents('li')[0] direction = $(el).attr('data-direction') - - # set previous state for undo - setUndo _.clone(user.get('stats')), _.clone(taskObj) - - scoring.score(model, taskObj.id, direction) + score(user, task.get('id'), direction) ### This is how we handle appExports.score for todos & dailies. Due to Derby's special handling of `checked={:task.completd}`, @@ -129,13 +145,7 @@ module.exports.app = (appExports, model) -> user.on 'set', 'tasks.*.completed', (i, completed, previous, isLocal, passed) -> return if passed? && passed.cron # Don't do this stuff on cron direction = if completed then 'up' else 'down' - - # set previous state for undo - taskObj = _.clone user.get("tasks.#{i}") - taskObj.completed = previous - setUndo _.clone(user.get('stats')), taskObj - - scoring.score(model, i, direction) + score(user, i, direction) ### Undo diff --git a/src/app/viewHelpers.coffee b/src/app/viewHelpers.coffee index c224dd308b..25a0d6af16 100644 --- a/src/app/viewHelpers.coffee +++ b/src/app/viewHelpers.coffee @@ -1,5 +1,5 @@ _ = require 'underscore' -algos = require './algos' +algos = require 'habitrpg-shared/script/algos' items = require('habitrpg-shared/script/items').items helpers = require('habitrpg-shared/script/helpers') diff --git a/src/server/api.coffee b/src/server/api.coffee index b7b8af798b..1b96fd194c 100644 --- a/src/server/api.coffee +++ b/src/server/api.coffee @@ -1,9 +1,9 @@ express = require 'express' router = new express.Router() -scoring = require '../app/scoring' _ = require 'underscore' -{ tnl } = require '../app/algos' +algos = require 'habitrpg-shared/script/algos' +{ tnl } = algos validator = require 'derby-auth/node_modules/validator' check = validator.check sanitize = validator.sanitize @@ -255,7 +255,8 @@ scoreTask = (req, res, next) -> model.refList "_#{type}List", "_user.tasks", "_user.#{type}Ids" model.at("_#{type}List").push task - delta = scoring.score(model, taskId, direction) + #FIXME + delta = algos.score(user.get(), taskId, direction) result = model.get '_user.stats' result.delta = delta res.json result diff --git a/src/server/deprecated.coffee b/src/server/deprecated.coffee index 3fcef2c8a3..68d5d2030d 100644 --- a/src/server/deprecated.coffee +++ b/src/server/deprecated.coffee @@ -1,7 +1,6 @@ express = require 'express' router = new express.Router() -scoring = require '../app/scoring' _ = require 'underscore' icalendar = require('icalendar') api = require './api'