mirror of
https://github.com/sudoxnym/habitica.git
synced 2026-07-14 07:52:15 +00:00
Fixed bug when calculating the reverse delta.
Added in a case for a todo with checklists so the gp and exp for those are reversed correctly. Added a couple test cases for checking then unchecking tasks.
This commit is contained in:
parent
65b3561fb0
commit
d0cebce605
3 changed files with 57 additions and 23 deletions
30
dist/habitrpg-shared.js
vendored
30
dist/habitrpg-shared.js
vendored
|
|
@ -14180,10 +14180,10 @@ api.wrap = function(user, main) {
|
|||
return nextDelta;
|
||||
};
|
||||
calculateReverseDelta = function() {
|
||||
var calc, closeEnough, currVal, diff, testVal;
|
||||
var calc, closeEnough, currVal, diff, nextDelta, testVal, _ref1;
|
||||
currVal = task.value < -47.27 ? -47.27 : task.value > 21.27 ? 21.27 : task.value;
|
||||
testVal = currVal + Math.pow(0.9747, currVal) * (direction === 'down' ? -1 : 1);
|
||||
closeEnough = 0.0001;
|
||||
closeEnough = 0.00001;
|
||||
while (true) {
|
||||
calc = testVal + Math.pow(0.9747, testVal);
|
||||
diff = currVal - calc;
|
||||
|
|
@ -14196,12 +14196,20 @@ api.wrap = function(user, main) {
|
|||
testVal += diff;
|
||||
}
|
||||
}
|
||||
return testVal - currVal;
|
||||
nextDelta = testVal - currVal;
|
||||
if (((_ref1 = task.checklist) != null ? _ref1.length : void 0) > 0) {
|
||||
if (task.type === 'todo') {
|
||||
nextDelta *= 1 + _.reduce(task.checklist, (function(m, i) {
|
||||
return m + (i.completed ? 1 : 0);
|
||||
}), 0);
|
||||
}
|
||||
}
|
||||
return nextDelta;
|
||||
};
|
||||
changeTaskValue = function(reverse) {
|
||||
changeTaskValue = function() {
|
||||
return _.times(options.times, function() {
|
||||
var nextDelta, _ref1;
|
||||
nextDelta = reverse ? calculateReverseDelta() : calculateDelta();
|
||||
nextDelta = !options.cron && direction === 'down' ? calculateReverseDelta() : calculateDelta();
|
||||
if (task.type !== 'reward') {
|
||||
if (user.preferences.automaticAllocation === true && user.preferences.allocationMode === 'taskbased' && !(task.type === 'todo' && direction === 'down')) {
|
||||
user.stats.training[task.attribute] += nextDelta;
|
||||
|
|
@ -14218,7 +14226,7 @@ api.wrap = function(user, main) {
|
|||
});
|
||||
};
|
||||
addPoints = function() {
|
||||
var afterStreak, gpMod, intBonus, perBonus, streakBonus, _crit;
|
||||
var afterStreak, currStreak, gpMod, intBonus, perBonus, streakBonus, _crit;
|
||||
_crit = (delta > 0 ? user.fns.crit() : 1);
|
||||
if (_crit > 1) {
|
||||
user._tmp.crit = _crit;
|
||||
|
|
@ -14227,7 +14235,7 @@ api.wrap = function(user, main) {
|
|||
stats.exp += Math.round(delta * intBonus * task.priority * _crit * 6);
|
||||
perBonus = 1 + user._statsComputed.per * .02;
|
||||
gpMod = delta * task.priority * _crit * perBonus;
|
||||
return stats.gp += task.streak ? (streakBonus = task.streak / 100 + 1, afterStreak = gpMod * streakBonus, gpMod > 0 ? user._tmp.streakBonus = afterStreak - gpMod : void 0, afterStreak) : gpMod;
|
||||
return stats.gp += task.streak ? (currStreak = direction === 'down' ? task.streak - 1 : task.streak, streakBonus = currStreak / 100 + 1, afterStreak = gpMod * streakBonus, currStreak > 0 ? gpMod > 0 ? user._tmp.streakBonus = afterStreak - gpMod : void 0 : void 0, afterStreak) : gpMod;
|
||||
};
|
||||
subtractPoints = function() {
|
||||
var conBonus, hpMod;
|
||||
|
|
@ -14269,8 +14277,8 @@ api.wrap = function(user, main) {
|
|||
task.streak = 0;
|
||||
}
|
||||
} else {
|
||||
changeTaskValue(delta < 0);
|
||||
if (delta < 0) {
|
||||
changeTaskValue();
|
||||
if (direction === 'down') {
|
||||
delta = calculateDelta();
|
||||
}
|
||||
addPoints();
|
||||
|
|
@ -14292,8 +14300,8 @@ api.wrap = function(user, main) {
|
|||
changeTaskValue();
|
||||
} else {
|
||||
task.dateCompleted = direction === 'up' ? new Date : void 0;
|
||||
changeTaskValue(delta < 0);
|
||||
if (delta < 0) {
|
||||
changeTaskValue();
|
||||
if (direction === 'down') {
|
||||
delta = calculateDelta();
|
||||
}
|
||||
addPoints();
|
||||
|
|
|
|||
|
|
@ -877,7 +877,7 @@ api.wrap = (user, main=true) ->
|
|||
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.0001
|
||||
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.
|
||||
|
|
@ -889,16 +889,25 @@ api.wrap = (user, main=true) ->
|
|||
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.
|
||||
testVal - currVal
|
||||
nextDelta = testVal - currVal
|
||||
|
||||
changeTaskValue = (reverse) ->
|
||||
# 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.
|
||||
nextDelta = if reverse then calculateReverseDelta() else calculateDelta()
|
||||
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 =====
|
||||
|
|
@ -930,9 +939,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
|
||||
|
||||
|
|
@ -965,9 +976,9 @@ api.wrap = (user, main=true) ->
|
|||
subtractPoints()
|
||||
task.streak = 0 unless user.stats.buffs.streaks
|
||||
else
|
||||
changeTaskValue(delta < 0)
|
||||
if delta < 0
|
||||
delta = 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
|
||||
|
|
@ -986,9 +997,9 @@ api.wrap = (user, main=true) ->
|
|||
#don't touch stats on cron
|
||||
else
|
||||
task.dateCompleted = if direction is 'up' then new Date else undefined
|
||||
changeTaskValue(delta < 0)
|
||||
if delta < 0
|
||||
delta = 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])
|
||||
|
|
|
|||
|
|
@ -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', ->
|
||||
|
|
|
|||
Loading…
Reference in a new issue