Merge branch 'develop' into hairlessbear-cron_dailies_fix
This commit is contained in:
+71
-43
@@ -80,6 +80,17 @@ api.shouldDo = (day, repeat, options={}) ->
|
||||
selected = repeat[api.dayMapping[api.startOfDay(_.defaults {now:day}, o).day()]]
|
||||
return selected
|
||||
|
||||
###
|
||||
------------------------------------------------------
|
||||
Level cap
|
||||
------------------------------------------------------
|
||||
###
|
||||
|
||||
api.maxLevel = 100
|
||||
|
||||
api.capByLevel = (lvl) ->
|
||||
if lvl > api.maxLevel then api.maxLevel else lvl
|
||||
|
||||
###
|
||||
------------------------------------------------------
|
||||
Scoring
|
||||
@@ -476,16 +487,13 @@ api.wrap = (user, main=true) ->
|
||||
|
||||
rebirth: (req, cb, ga) ->
|
||||
# Cost is 8 Gems ($2)
|
||||
if (user.balance < 2 && user.stats.lvl < 100)
|
||||
if (user.balance < 2 && user.stats.lvl < api.maxLevel)
|
||||
return cb? {code:401,message: i18n.t('notEnoughGems', req.language)}
|
||||
# only charge people if they are under level 100 - ryan
|
||||
if user.stats.lvl < 100
|
||||
# only charge people if they are under the max level - ryan
|
||||
if user.stats.lvl < api.maxLevel
|
||||
user.balance -= 2
|
||||
# Save off user's level, for calculating achievement eligibility later
|
||||
if user.stats.lvl < 100
|
||||
lvl = user.stats.lvl
|
||||
else
|
||||
lvl = 100
|
||||
lvl = api.capByLevel(user.stats.lvl)
|
||||
# Turn tasks yellow, zero out streaks
|
||||
_.each user.tasks, (task) ->
|
||||
unless task.type is 'reward'
|
||||
@@ -935,7 +943,7 @@ api.wrap = (user, main=true) ->
|
||||
else
|
||||
return cb?({code:401,message:i18n.t('notEnoughGems', req.language)}) unless user.balance >= .75
|
||||
user.balance -= .75
|
||||
_.merge user.stats, {str: 0, con: 0, per: 0, int: 0, points: user.stats.lvl}
|
||||
_.merge user.stats, {str: 0, con: 0, per: 0, int: 0, points: api.capByLevel(user.stats.lvl)}
|
||||
user.flags.classSelected = false
|
||||
ga?.event('behavior', 'gems', 'changeClass').send()
|
||||
#'stats.points': this is handled on the server
|
||||
@@ -946,7 +954,7 @@ api.wrap = (user, main=true) ->
|
||||
user.flags.classSelected = true
|
||||
user.preferences.disableClasses = true
|
||||
user.preferences.autoAllocate = true
|
||||
user.stats.str = user.stats.lvl
|
||||
user.stats.str = api.capByLevel(user.stats.lvl)
|
||||
user.stats.points = 0
|
||||
cb? null, _.pick(user,$w 'stats flags preferences')
|
||||
|
||||
@@ -1068,11 +1076,10 @@ api.wrap = (user, main=true) ->
|
||||
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 =====
|
||||
# (Only for up-scoring, ignore up-onlies and rewards)
|
||||
if direction is 'up' and !(task.type is 'habit' and !task.down)
|
||||
if direction is 'up' # Make progress on quest based on STR
|
||||
user.party.quest.progress.up = user.party.quest.progress.up || 0;
|
||||
user.party.quest.progress.up += (nextDelta * (1 + (user._statsComputed.str / 200))) if task.type in ['daily','todo']
|
||||
user.party.quest.progress.up += (nextDelta * (0.5 + (user._statsComputed.str / 400))) if task.type is 'habit'
|
||||
task.value += nextDelta
|
||||
delta += nextDelta
|
||||
|
||||
@@ -1113,9 +1120,17 @@ api.wrap = (user, main=true) ->
|
||||
hpMod = delta * conBonus * task.priority * 2 # constant 2 multiplier for better results
|
||||
stats.hp += Math.round(hpMod * 10) / 10 # round to 1dp
|
||||
|
||||
gainMP = (delta) ->
|
||||
delta *= user._tmp.crit or 1
|
||||
user.stats.mp += delta
|
||||
user.stats.mp = user._statsComputed.maxMP if user.stats.mp >= user._statsComputed.maxMP
|
||||
user.stats.mp = 0 if user.stats.mp < 0
|
||||
|
||||
# ===== starting to actually do stuff, most of above was definitions =====
|
||||
switch task.type
|
||||
when 'habit'
|
||||
changeTaskValue()
|
||||
gainMP(_.max([0.25, (.0025 * user._statsComputed.maxMP)]) * if direction is 'down' then -1 else 1)
|
||||
# Add habit value to habit-history (if different)
|
||||
if (delta > 0) then addPoints() else subtractPoints()
|
||||
|
||||
@@ -1134,6 +1149,7 @@ api.wrap = (user, main=true) ->
|
||||
task.streak = 0 unless user.stats.buffs.streaks
|
||||
else
|
||||
changeTaskValue()
|
||||
gainMP(_.max([1, (.01 * user._statsComputed.maxMP)]) * if direction is 'down' then -1 else 1)
|
||||
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
|
||||
@@ -1160,12 +1176,7 @@ api.wrap = (user, main=true) ->
|
||||
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])
|
||||
mpDelta = _.max([(multiplier), (.01 * user._statsComputed.maxMP * multiplier)])
|
||||
mpDelta *= user._tmp.crit or 1
|
||||
mpDelta *= -1 if direction is 'down' # unticking a todo
|
||||
user.stats.mp += mpDelta
|
||||
user.stats.mp = user._statsComputed.maxMP if user.stats.mp >= user._statsComputed.maxMP
|
||||
user.stats.mp = 0 if user.stats.mp < 0 # BUT DO WE WANT THIS? SEE COMMIT DESCRIPTION
|
||||
gainMP(_.max([(multiplier), (.01 * user._statsComputed.maxMP * multiplier)]) * if direction is 'down' then -1 else 1)
|
||||
|
||||
when 'reward'
|
||||
# Don't adjust values for rewards
|
||||
@@ -1222,7 +1233,9 @@ api.wrap = (user, main=true) ->
|
||||
|
||||
crit: (stat='str', chance=.03) ->
|
||||
#console.log("Crit Chance:"+chance*(1+user._statsComputed[stat]/100))
|
||||
if user.fns.predictableRandom() <= chance*(1+user._statsComputed[stat]/100) then 1.5 + (.02*user._statsComputed[stat])
|
||||
s = user._statsComputed[stat]
|
||||
if user.fns.predictableRandom() <= chance*(1 + s/100)
|
||||
1.5 + 4*s/(s + 200)
|
||||
else 1
|
||||
|
||||
###
|
||||
@@ -1342,7 +1355,8 @@ api.wrap = (user, main=true) ->
|
||||
_.invert(stats)[_.min stats]
|
||||
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)]
|
||||
lvlDiv7 = user.stats.lvl / 7
|
||||
ideal = [(lvlDiv7 * 3), (lvlDiv7 * 2), lvlDiv7, lvlDiv7]
|
||||
# Primary, secondary etc. attributes aren't explicitly defined, so hardcode them. In order as above
|
||||
preference = switch user.stats.class
|
||||
when "wizard" then ["int", "per", "con", "str"]
|
||||
@@ -1378,6 +1392,10 @@ api.wrap = (user, main=true) ->
|
||||
user.stats.lvl++
|
||||
tnl = api.tnl(user.stats.lvl)
|
||||
|
||||
user.stats.hp = 50
|
||||
|
||||
continue if user.stats.lvl > api.maxLevel
|
||||
|
||||
# Auto-allocate a point, or give them a new manual point
|
||||
if user.preferences.automaticAllocation
|
||||
user.fns.autoAllocate()
|
||||
@@ -1388,8 +1406,6 @@ api.wrap = (user, main=true) ->
|
||||
user.stats.points = 0
|
||||
# This happens after dropping level with Fix Character Values and perhaps from other causes.
|
||||
# TODO: Subtract points from attributes in the same manner as on death.
|
||||
|
||||
user.stats.hp = 50
|
||||
user.stats.exp = stats.exp
|
||||
|
||||
# Set flags when they unlock features
|
||||
@@ -1417,7 +1433,7 @@ api.wrap = (user, main=true) ->
|
||||
dialog: i18n.t('messageFoundQuest', {questText: content.quests[k].text(req.language)}, req.language)
|
||||
if !user.flags.rebirthEnabled and (user.stats.lvl >= 50 or user.achievements.ultimateGear or user.achievements.beastMaster)
|
||||
user.flags.rebirthEnabled = true
|
||||
if user.stats.lvl >= 100 and !user.flags.freeRebirth
|
||||
if user.stats.lvl >= api.maxLevel and !user.flags.freeRebirth
|
||||
user.flags.freeRebirth = true
|
||||
|
||||
###
|
||||
@@ -1493,34 +1509,50 @@ api.wrap = (user, main=true) ->
|
||||
|
||||
# Tally each task
|
||||
todoTally = 0
|
||||
dailyChecked = 0 # how many dailies were checked?
|
||||
dailyDueUnchecked = 0 # how many dailies were due but not checked?
|
||||
user.party.quest.progress.down ?= 0
|
||||
user.todos.concat(user.dailys).forEach (task) ->
|
||||
return unless task
|
||||
|
||||
{id, type, completed, repeat} = task
|
||||
|
||||
return if (type is 'daily') && !completed && user.stats.buffs.stealth && user.stats.buffs.stealth-- # User "evades" a certain number of uncompleted dailies
|
||||
|
||||
|
||||
# Deduct experience for missed Daily tasks, but not for Todos (just increase todo's value)
|
||||
unless completed
|
||||
scheduleMisses = daysMissed
|
||||
# Deduct points for missed Daily tasks, but not for Todos (just increase todo's value)
|
||||
EvadeTask = 0
|
||||
scheduleMisses = daysMissed
|
||||
if completed
|
||||
if type is 'daily'
|
||||
dailyChecked += 1
|
||||
else
|
||||
# for dailys which have repeat dates, need to calculate how many they've missed according to their own schedule
|
||||
if (type is 'daily') and repeat
|
||||
scheduleMisses = 0
|
||||
_.times daysMissed, (n) ->
|
||||
thatDay = moment(now).subtract({days: n + 1})
|
||||
scheduleMisses++ if api.shouldDo(thatDay, repeat, user.preferences)
|
||||
if scheduleMisses > 0
|
||||
perfect = false if type is 'daily'
|
||||
delta = user.ops.score({params:{id:task.id, direction:'down'}, query:{times:scheduleMisses, cron:true}});
|
||||
if api.shouldDo(thatDay, repeat, user.preferences)
|
||||
scheduleMisses++
|
||||
if user.stats.buffs.stealth
|
||||
user.stats.buffs.stealth--
|
||||
EvadeTask++
|
||||
if scheduleMisses > EvadeTask
|
||||
if type is 'daily'
|
||||
perfect = false
|
||||
if task.checklist?.length > 0 # Partially completed checklists dock fewer mana points
|
||||
fractionChecked = _.reduce(task.checklist,((m,i)->m+(if i.completed then 1 else 0)),0) / task.checklist.length
|
||||
dailyDueUnchecked += (1 - fractionChecked)
|
||||
dailyChecked += fractionChecked
|
||||
else
|
||||
dailyDueUnchecked += 1
|
||||
delta = user.ops.score({params:{id:task.id, direction:'down'}, query:{times:(scheduleMisses-EvadeTask), cron:true}}); # this line occurs for todos or dailys
|
||||
user.party.quest.progress.down += delta if type is 'daily'
|
||||
|
||||
switch type
|
||||
when 'daily'
|
||||
# This occurs whether or not the task is completed
|
||||
(task.history ?= []).push({ date: +new Date, value: task.value })
|
||||
task.completed = false
|
||||
_.each task.checklist, ((i)->i.completed=false;true)
|
||||
if completed || (scheduleMisses > 0)
|
||||
_.each task.checklist, ((i)->i.completed=false;true) # this should not happen for grey tasks unless they are completed
|
||||
when 'todo'
|
||||
#get updated value
|
||||
absVal = if (completed) then Math.abs(task.value) else task.value
|
||||
@@ -1555,15 +1587,14 @@ api.wrap = (user, main=true) ->
|
||||
if perfect
|
||||
user.achievements.perfect ?= 0
|
||||
user.achievements.perfect++
|
||||
if user.stats.lvl < 100
|
||||
lvlDiv2 = Math.ceil(user.stats.lvl/2)
|
||||
else
|
||||
lvlDiv2 = 50
|
||||
lvlDiv2 = Math.ceil(api.capByLevel(user.stats.lvl) / 2)
|
||||
{str:lvlDiv2,int:lvlDiv2,per:lvlDiv2,con:lvlDiv2,stealth:0,streaks:false}
|
||||
else clearBuffs
|
||||
|
||||
# Add 10 MP, or 10% of max MP if that'd be more. Perform this after Perfect Day for maximum benefit
|
||||
user.stats.mp += _.max([10,.1 * user._statsComputed.maxMP])
|
||||
# Adjust for fraction of dailies completed
|
||||
dailyChecked=1 if dailyDueUnchecked is 0 and dailyChecked is 0
|
||||
user.stats.mp += _.max([10,.1 * user._statsComputed.maxMP]) * dailyChecked / (dailyDueUnchecked + dailyChecked)
|
||||
user.stats.mp = user._statsComputed.maxMP if user.stats.mp > user._statsComputed.maxMP
|
||||
|
||||
# Analytics
|
||||
@@ -1643,10 +1674,7 @@ api.wrap = (user, main=true) ->
|
||||
else
|
||||
+val[stat] or 0
|
||||
, 0
|
||||
if user.stats.lvl < 100
|
||||
m[stat] += (user.stats.lvl - 1) / 2
|
||||
else
|
||||
m[stat] += 50
|
||||
m[stat] += Math.floor(api.capByLevel(user.stats.lvl) / 2)
|
||||
m
|
||||
, {}
|
||||
computed.maxMP = computed.int*2 + 30
|
||||
|
||||
Reference in New Issue
Block a user