habitrpg-shared: *almost* working wth new scoring (c0cf9780fe) - need to fix for cron, API, and other misc bugs

This commit is contained in:
Tyler Renelle 2013-05-19 23:48:51 +01:00
parent 6a36f4bd1d
commit 0b445df909
9 changed files with 46 additions and 112 deletions

View file

@ -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",

View file

@ -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

View file

@ -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]

View file

@ -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')

View file

@ -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)

View file

@ -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

View file

@ -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')

View file

@ -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

View file

@ -1,7 +1,6 @@
express = require 'express'
router = new express.Router()
scoring = require '../app/scoring'
_ = require 'underscore'
icalendar = require('icalendar')
api = require './api'