diff --git a/dist/habitrpg-shared.js b/dist/habitrpg-shared.js index 74273a5cdf..a6b307b39b 100644 --- a/dist/habitrpg-shared.js +++ b/dist/habitrpg-shared.js @@ -63,7 +63,7 @@ process.chdir = function (dir) { }; },{}],3:[function(require,module,exports){ -var global=self;/** +var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};/** * @license * Lo-Dash 2.4.1 (Custom Build) * Build: `lodash modern -o ./dist/lodash.js` @@ -11777,6 +11777,9 @@ var process=require("__browserify_process");(function() { } } if (task.type !== 'reward') { + if (user.preferences.automaticAllocation === true && user.preferences.allocationMode === 'taskbased') { + user.stats.training[task.attribute] += nextDelta; + } adjustAmt = nextDelta; if (direction === 'up' && task.type !== 'reward' && !(task.type === 'habit' && !task.down)) { adjustAmt = nextDelta * (1 + user._statsComputed.str * .004); @@ -12055,8 +12058,70 @@ var process=require("__browserify_process");(function() { {update} if aggregated changes, pass in userObj as update. otherwise commits will be made immediately */ + autoAllocate: function() { + var diff, ideal, preference, suggested; + switch (user.preferences.allocationMode) { + case "flat": + suggested = Math.min(user.stats.str, user.stats.int, user.stats.con, user.stats.per); + if (user.stats.int === suggested) { + return "int"; + } else if (user.stats.per === suggested) { + return "per"; + } else if (user.stats.str === suggested) { + return "str"; + } else { + return "con"; + } + break; + case "classbased": + ideal = [user.stats.lvl / 7 * 3, user.stats.lvl / 7 * 2, user.stats.lvl / 7, user.stats.lvl / 7]; + switch (user.stats["class"]) { + case "wizard": + preference = ["int", "per", "con", "str"]; + break; + case "rogue": + preference = ["per", "str", "int", "con"]; + break; + case "healer": + preference = ["con", "int", "str", "per"]; + break; + default: + preference = ["str", "con", "per", "int"]; + } + diff = [user.stats[preference[0]] - ideal[0], user.stats[preference[1]] - ideal[1], user.stats[preference[2]] - ideal[2], user.stats[preference[3]] - ideal[3]]; + suggested = _.findIndex(diff, (function(val) { + if (val === _.min(diff)) { + return true; + } + })); + if (suggested === -1) { + return "str"; + } else { + return preference[suggested]; + } + break; + case "taskbased": + suggested = _.findKey(user.stats.training, (function(val) { + if (val === _.max(user.stats.training)) { + return val; + } + })); + user.stats.training.str = 0; + user.stats.training.int = 0; + user.stats.training.con = 0; + user.stats.training.per = 0; + if (suggested === void 0) { + return "str"; + } else { + return suggested; + } + break; + default: + return "str"; + } + }, updateStats: function(stats) { - var suggested, tallies, tnl; + var suggested, tnl; if (stats.hp <= 0) { return user.stats.hp = 0; } @@ -12075,22 +12140,7 @@ var process=require("__browserify_process");(function() { user.stats.lvl++; tnl = api.tnl(user.stats.lvl); if (user.preferences.automaticAllocation) { - tallies = _.reduce(user.tasks, (function(m, v) { - m[v.attribute || 'str'] += v.value; - return m; - }), { - str: 0, - int: 0, - con: 0, - per: 0 - }); - suggested = _.reduce(tallies, (function(m, v, k) { - if (v > tallies[m]) { - return k; - } else { - return m; - } - }), 'str'); + suggested = user.fns.autoAllocate(); user.stats[suggested]++; } else { user.stats.points = user.stats.lvl - (user.stats.con + user.stats.str + user.stats.per + user.stats.int); diff --git a/script/index.coffee b/script/index.coffee index 68bf64312a..fcc336e390 100644 --- a/script/index.coffee +++ b/script/index.coffee @@ -747,6 +747,7 @@ api.wrap = (user) -> nextDelta *= task.checklist.length unless task.type is 'reward' + if (user.preferences.automaticAllocation is true and user.preferences.allocationMode is 'taskbased') then user.stats.training[task.attribute] += nextDelta adjustAmt = nextDelta # ===== STRENGTH ===== # (Only for up-scoring, ignore up-onlies and rewards) @@ -1004,6 +1005,43 @@ api.wrap = (user) -> {stats} new stats {update} if aggregated changes, pass in userObj as update. otherwise commits will be made immediately ### + autoAllocate: -> + switch user.preferences.allocationMode + when "flat" + suggested = Math.min(user.stats.str, user.stats.int, user.stats.con, user.stats.per) + if user.stats.int is suggested # In case of ties, favor INT first, to get the next point sooner + return "int" + else if user.stats.per is suggested # Then favor PER, it's a god stat + return "per" + else if user.stats.str is suggested # Then favor STR, everyone loves crits + return "str" + else + return "con" # CON, the unsexiest of attributes + when "classbased" + # Attributes get 3:2:1:1 per 7 levels. + ideal = [(user.stats.lvl / 7 * 3), (user.stats.lvl / 7 * 2), (user.stats.lvl / 7), (user.stats.lvl / 7)] + # Primary, secondary etc. attributes aren't explicitly defined, so hardcode them. In order as above + switch user.stats.class + when "wizard" then preference = ["int", "per", "con", "str"] + when "rogue" then preference = ["per", "str", "int", "con"] + when "healer" then preference = ["con", "int", "str", "per"] + else preference = ["str", "con", "per", "int"] + # Get the difference between the ideal attribute spread according to level, and the user's current spread. + diff = [(user.stats[preference[0]]-ideal[0]),(user.stats[preference[1]]-ideal[1]),(user.stats[preference[2]]-ideal[2]),(user.stats[preference[3]]-ideal[3])] + suggested = _.findIndex(diff, ((val) -> if val is _.min(diff) then true)) # Returns the index of the first attribute that's furthest behind the ideal + if suggested is -1 then return "str" else return preference[suggested] # If _.findIndex failed, we'd get a -1... + when "taskbased" + suggested = _.findKey(user.stats.training, ((val) -> if val is _.max(user.stats.training) then val)) # Returns the stat that's been trained up the most this level + # FIXME Reset training for this level. Tried _.each but couldn't get it to take. + user.stats.training.str = 0 + user.stats.training.int = 0 + user.stats.training.con = 0 + user.stats.training.per = 0 + if suggested is undefined then return "str" else return suggested # Failed _.findkey gives undefined + # tallies = _.reduce user.tasks, ((m,v)-> m[v.attribute or 'str'] += v.value;m), {str:0,int:0,con:0,per:0} + # suggested = _.reduce tallies, ((m,v,k)-> if v>tallies[m] then k else m), 'str' + else return "str" # if all else fails, dump into STR + updateStats: (stats) -> # Game Over return user.stats.hp=0 if stats.hp <= 0 @@ -1029,8 +1067,7 @@ api.wrap = (user) -> # Auto-allocate a point, or give them a new manual point if user.preferences.automaticAllocation - tallies = _.reduce user.tasks, ((m,v)-> m[v.attribute or 'str'] += v.value;m), {str:0,int:0,con:0,per:0} - suggested = _.reduce tallies, ((m,v,k)-> if v>tallies[m] then k else m), 'str' + suggested = user.fns.autoAllocate() user.stats[suggested]++ else # add new allocatable points. We could do user.stats.points++, but this does a fail-safe just in case