chore(github): merge pr #327

This commit is contained in:
Matteo Pagliazzi 2014-10-07 17:01:06 +02:00
commit 166d53ac1b
3 changed files with 1236 additions and 592 deletions

1712
dist/habitrpg-shared.js vendored

File diff suppressed because it is too large Load diff

View file

@ -855,28 +855,69 @@ api.wrap = (user, main=true) ->
delta = 0
calculateDelta = ->
# Calculates the next task.value based on direction
# Uses a capped inverse log y=.95^x, y>= -5
# Min/max on task redness
currVal =
if task.value < -47.27 then -47.27
else if task.value > 21.27 then 21.27
else task.value
nextDelta = Math.pow(0.9747, currVal) * (if direction is 'down' then -1 else 1)
# Checklists
if task.checklist?.length > 0
# If the Daily, only dock them them a portion based on their checklist completion
if direction is 'down' and task.type is 'daily' and options.cron
nextDelta *= (1 - _.reduce(task.checklist,((m,i)->m+(if i.completed then 1 else 0)),0) / task.checklist.length)
# If To-Do, point-match the TD per checklist item completed
if task.type is 'todo'
nextDelta *= (1 + _.reduce(task.checklist,((m,i)->m+(if i.completed then 1 else 0)),0))
nextDelta
calculateReverseDelta = ->
# Approximates the reverse delta for the task value
# This is meant to return the task value to its original value when unchecking a task.
# First, calculate the the value using the normal way for our first guess although
# it will be a bit off
currVal =
if task.value < -47.27 then -47.27
else if task.value > 21.27 then 21.27
else task.value
testVal = currVal + Math.pow(0.9747, currVal) * (if direction is 'down' then -1 else 1)
# Now keep moving closer to the original value until we get "close enough"
closeEnough = 0.00001
while true
# Check how close we are to the original value by computing the delta off our guess
# and looking at the difference between that and our current value.
calc = (testVal) + Math.pow(0.9747, testVal)
diff = currVal-calc
if Math.abs(diff) < closeEnough
break
if diff > 0
testVal -= diff
else
testVal += diff
# When we get close enough, return the difference between our approximated value
# and the current value. This will be the delta calculated from the original value
# before the task was checked.
nextDelta = testVal - currVal
# Checklists
if task.checklist?.length > 0
# If To-Do, point-match the TD per checklist item completed
if task.type is 'todo'
nextDelta *= (1 + _.reduce(task.checklist,((m,i)->m+(if i.completed then 1 else 0)),0))
nextDelta
changeTaskValue = ->
# If multiple days have passed, multiply times days missed
_.times options.times, ->
# Each iteration calculate the nextDelta, which is then accumulated in the total delta.
# Calculates the next task.value based on direction
# Uses a capped inverse log y=.95^x, y>= -5
# Min/max on task redness
currVal =
if task.value < -47.27 then -47.27
else if task.value > 21.27 then 21.27
else task.value
nextDelta = Math.pow(0.9747, currVal) * (if direction is 'down' then -1 else 1)
# Checklists
if task.checklist?.length > 0
# If the Daily, only dock them them a portion based on their checklist completion
if direction is 'down' and task.type is 'daily' and options.cron
nextDelta *= (1 - _.reduce(task.checklist,((m,i)->m+(if i.completed then 1 else 0)),0) / task.checklist.length)
# If To-Do, point-match the TD per checklist item completed
if task.type is 'todo'
nextDelta *= (1 + _.reduce(task.checklist,((m,i)->m+(if i.completed then 1 else 0)),0))
nextDelta = if not options.cron and direction is 'down' then calculateReverseDelta() else calculateDelta()
unless task.type is 'reward'
if (user.preferences.automaticAllocation is true and user.preferences.allocationMode is 'taskbased' and !(task.type is 'todo' and direction is 'down')) then user.stats.training[task.attribute] += nextDelta
# ===== STRENGTH =====
@ -908,9 +949,11 @@ api.wrap = (user, main=true) ->
gpMod = (delta * task.priority * _crit * perBonus)
stats.gp +=
if task.streak
streakBonus = task.streak / 100 + 1 # eg, 1-day streak is 1.1, 2-day is 1.2, etc
currStreak = if direction is 'down' then task.streak-1 else task.streak
streakBonus = currStreak / 100 + 1 # eg, 1-day streak is 1.01, 2-day is 1.02, etc
afterStreak = gpMod * streakBonus
user._tmp.streakBonus = afterStreak - gpMod if (gpMod > 0) # keep this on-hand for later, so we can notify streak-bonus
if currStreak > 0
user._tmp.streakBonus = afterStreak - gpMod if (gpMod > 0) # keep this on-hand for later, so we can notify streak-bonus
afterStreak
else gpMod
@ -925,7 +968,7 @@ api.wrap = (user, main=true) ->
switch task.type
when 'habit'
calculateDelta()
changeTaskValue()
# Add habit value to habit-history (if different)
if (delta > 0) then addPoints() else subtractPoints()
@ -939,11 +982,13 @@ api.wrap = (user, main=true) ->
when 'daily'
if options.cron
calculateDelta()
changeTaskValue()
subtractPoints()
task.streak = 0 unless user.stats.buffs.streaks
else
calculateDelta()
changeTaskValue()
if direction is 'down'
delta = calculateDelta() # recalculate delta for unchecking so the gp and exp come out correctly
addPoints() # obviously for delta>0, but also a trick to undo accidental checkboxes
if direction is 'up'
task.streak = if task.streak then task.streak + 1 else 1
@ -958,11 +1003,13 @@ api.wrap = (user, main=true) ->
when 'todo'
if options.cron
calculateDelta()
changeTaskValue()
#don't touch stats on cron
else
task.dateCompleted = if direction is 'up' then new Date else undefined
calculateDelta()
changeTaskValue()
if direction is 'down'
delta = calculateDelta() # recalculate delta for unchecking so the gp and exp come out correctly
addPoints() # obviously for delta>0, but also a trick to undo accidental checkboxes
# MP++ per checklist item in ToDo, bonus per CLI
multiplier = _.max([(_.reduce(task.checklist,((m,i)->m+(if i.completed then 1 else 0)),1)),1])
@ -975,7 +1022,7 @@ api.wrap = (user, main=true) ->
when 'reward'
# Don't adjust values for rewards
calculateDelta()
changeTaskValue()
# purchase item
stats.gp -= Math.abs(task.value)
num = parseFloat(task.value).toFixed(2)

View file

@ -93,6 +93,11 @@ expectNoChange = (before,after) ->
_.each $w('stats items gear dailys todos rewards flags preferences'), (attr)->
expect(after[attr]).to.eql before[attr]
expectClosePoints = (before, after, taskType) ->
expect( Math.abs(after.stats.exp - before.stats.exp) ).to.be.lessThan 0.0001
expect( Math.abs(after.stats.gp - before.stats.gp) ).to.be.lessThan 0.0001
expect( Math.abs(after["#{taskType}s"][0].value - before["#{taskType}s"][0].value) ).to.be.lessThan 0.0001
expectDayResetNoDamage = (b,a) ->
[before,after] = [_.cloneDeep(b), _.cloneDeep(a)]
_.each after.dailys, (task,i) ->
@ -379,10 +384,20 @@ describe 'Simple Scoring', ->
@after.ops.score {params: {id: @after.dailys[0].id, direction: 'up'}}
expectGainedPoints(@before, @after,'daily')
it 'Dailys : Up, Down', ->
@after.ops.score {params: {id: @after.dailys[0].id, direction: 'up'}}
@after.ops.score {params: {id: @after.dailys[0].id, direction: 'down'}}
expectClosePoints(@before, @after, 'daily')
it 'Todos : Up', ->
@after.ops.score {params: {id: @after.todos[0].id, direction: 'up'}}
expectGainedPoints(@before, @after,'todo')
it 'Todos : Up, Down', ->
@after.ops.score {params: {id: @after.todos[0].id, direction: 'up'}}
@after.ops.score {params: {id: @after.todos[0].id, direction: 'down'}}
expectClosePoints(@before, @after, 'todo')
describe 'Cron', ->
it 'computes shouldCron', ->