Merge pull request #4812 from HabitRPG/blade-rebalancing

Merge Rebalancing branch from habitrpg-shared and preserve commit history
This commit is contained in:
Alys
2015-03-07 05:54:43 +10:00
4 changed files with 7379 additions and 7306 deletions
+7295 -7255
View File
File diff suppressed because it is too large Load Diff
+43 -34
View File
@@ -3,7 +3,7 @@ api = module.exports
moment = require 'moment'
i18n = require './i18n.coffee'
t = (string, vars) ->
func = (lang) ->
func = (lang) ->
vars ?= {a: 'a'}
i18n.t(string, vars, lang)
func.i18nLangFunc = true #Trick to recognize this type of function
@@ -53,7 +53,7 @@ _.each api.mystery, (v,k)->v.key = k
gear =
weapon:
base:
0:
0:
text: t('weaponBase0Text'), notes: t('weaponBase0Notes'), value:0
warrior:
0: text: t('weaponWarrior0Text'), notes: t('weaponWarrior0Notes'), value:0
@@ -370,7 +370,7 @@ gear =
springWarrior: event: events.spring, specialClass: 'warrior', text: t('headAccessorySpecialSpringWarriorText'), notes: t('headAccessorySpecialSpringWarriorNotes'), value: 20
springMage: event: events.spring, specialClass: 'wizard', text: t('headAccessorySpecialSpringMageText'), notes: t('headAccessorySpecialSpringMageNotes'), value: 20
springHealer: event: events.spring, specialClass: 'healer', text: t('headAccessorySpecialSpringHealerText'), notes: t('headAccessorySpecialSpringHealerNotes'), value: 20
mystery:
201403: text: t('headAccessoryMystery201403Text'), notes: t('headAccessoryMystery201403Notes'), mystery:'201403', value: 0
201404: text: t('headAccessoryMystery201404Text'), notes: t('headAccessoryMystery201404Notes'), mystery:'201404', value: 0
@@ -479,6 +479,8 @@ api.gearTypes = gearTypes
#
diminishingReturns = (bonus, max, halfway=max/2) -> max*(bonus/(bonus+halfway))
calculateBonus = (value, stat, crit=1, stat_scale=0.5) -> (if value < 0 then 1 else value+1) + (stat * stat_scale * crit)
api.spells =
wizard:
@@ -489,13 +491,11 @@ api.spells =
target: 'task'
notes: t('spellWizardFireballNotes')
cast: (user, target) ->
# I seriously have no idea what I'm doing here. I'm just mashing buttons until numbers seem right-ish. Anyone know math?
bonus = user._statsComputed.int * user.fns.crit('per')
target.value += diminishingReturns(bonus*.02, 4)
bonus *= Math.ceil ((if target.value < 0 then 1 else target.value+1) *.075)
#console.log {bonus, expBonus:bonus,upBonus:bonus*.1}
user.stats.exp += diminishingReturns(bonus,75)
user.party.quest.progress.up += diminishingReturns(bonus*.1,50,30)
user.party.quest.progress.up ?= 0
user.party.quest.progress.up += Math.ceil(user._statsComputed.int * .1)
mpheal:
text: t('spellWizardMPHealText')
@@ -505,9 +505,8 @@ api.spells =
notes: t('spellWizardMPHealNotes'),
cast: (user, target)->
_.each target, (member) ->
bonus = Math.ceil(user._statsComputed.int * .1)
bonus = 25 if bonus > 25 #prevent ability to replenish own mp infinitely
member.stats.mp += bonus
bonus = user._statsComputed.int
member.stats.mp += Math.ceil(diminishingReturns(bonus, 25, 125)) # maxes out at 25
earth:
text: t('spellWizardEarthText')
@@ -517,8 +516,9 @@ api.spells =
notes: t('spellWizardEarthNotes'),
cast: (user, target) ->
_.each target, (member) ->
bonus = user._statsComputed.int
member.stats.buffs.int ?= 0
member.stats.buffs.int += Math.ceil(user._statsComputed.int * .05)
member.stats.buffs.int += Math.ceil(diminishingReturns(bonus, 30,200))
frost:
text: t('spellWizardFrostText'),
@@ -537,8 +537,11 @@ api.spells =
target: 'task'
notes: t('spellWarriorSmashNotes')
cast: (user, target) ->
target.value += 2.5 * (user._statsComputed.str / (user._statsComputed.str + 50)) * user.fns.crit('con')
user.party.quest.progress.up += Math.ceil(user._statsComputed.str * .2)
bonus = user._statsComputed.str * user.fns.crit('con')
target.value += diminishingReturns(bonus, 2.5, 35)
user.party.quest.progress.up ?= 0
user.party.quest.progress.up += diminishingReturns(bonus, 55, 70)
defensiveStance:
text: t('spellWarriorDefensiveStanceText')
mana: 25
@@ -546,8 +549,10 @@ api.spells =
target: 'self'
notes: t('spellWarriorDefensiveStanceNotes')
cast: (user, target) ->
bonus = user._statsComputed.con
user.stats.buffs.con ?= 0
user.stats.buffs.con += Math.ceil(user._statsComputed.con * .05)
user.stats.buffs.con += Math.ceil(diminishingReturns(bonus, 40, 200))
valorousPresence:
text: t('spellWarriorValorousPresenceText')
mana: 20
@@ -556,8 +561,10 @@ api.spells =
notes: t('spellWarriorValorousPresenceNotes')
cast: (user, target) ->
_.each target, (member) ->
bonus = user._statsComputed.str
member.stats.buffs.str ?= 0
member.stats.buffs.str += Math.ceil(user._statsComputed.str * .05)
member.stats.buffs.str += Math.ceil(diminishingReturns(bonus, 20, 200))
intimidate:
text: t('spellWarriorIntimidateText')
mana: 15
@@ -566,8 +573,9 @@ api.spells =
notes: t('spellWarriorIntimidateNotes')
cast: (user, target) ->
_.each target, (member) ->
bonus = user._statsComputed.con
member.stats.buffs.con ?= 0
member.stats.buffs.con += Math.ceil(user._statsComputed.con * .03)
member.stats.buffs.con += Math.ceil(diminishingReturns(bonus,24,200))
rogue:
pickPocket:
@@ -577,8 +585,9 @@ api.spells =
target: 'task'
notes: t('spellRoguePickPocketNotes')
cast: (user, target) ->
bonus = (if target.value < 0 then 1 else target.value+2) + (user._statsComputed.per * 0.5)
user.stats.gp += 25 * (bonus / (bonus + 75))
bonus = calculateBonus(target.value, user._statsComputed.per)
user.stats.gp += diminishingReturns(bonus, 25, 75)
backStab:
text: t('spellRogueBackStabText')
mana: 15
@@ -587,11 +596,10 @@ api.spells =
notes: t('spellRogueBackStabNotes')
cast: (user, target) ->
_crit = user.fns.crit('str', .3)
target.value += _crit * .03
bonus = (if target.value < 0 then 1 else target.value+1) * _crit
user.stats.exp += bonus
user.stats.gp += bonus
# user.party.quest.progress.up += bonus if user.party.quest.key # remove hurting bosses for rogues, seems OP for now
bonus = calculateBonus(target.value, user._statsComputed.str, _crit)
user.stats.exp += diminishingReturns(bonus, 75, 50)
user.stats.gp += diminishingReturns(bonus, 18, 75)
toolsOfTrade:
text: t('spellRogueToolsOfTradeText')
mana: 25
@@ -599,10 +607,11 @@ api.spells =
target: 'party'
notes: t('spellRogueToolsOfTradeNotes')
cast: (user, target) ->
## lasts 24 hours ##
_.each target, (member) ->
bonus = user._statsComputed.per
member.stats.buffs.per ?= 0
member.stats.buffs.per += Math.ceil(user._statsComputed.per * .03)
member.stats.buffs.per += Math.ceil(diminishingReturns(bonus, 400, 100))
stealth:
text: t('spellRogueStealthText')
mana: 45
@@ -633,7 +642,7 @@ api.spells =
cast: (user, target) ->
_.each user.tasks, (target) ->
return if target.type is 'reward'
target.value += 1.5 * (user._statsComputed.int / (user._statsComputed.int + 40))
target.value += 4 * (user._statsComputed.int / (user._statsComputed.int + 40))
protectAura:
text: t('spellHealerProtectAuraText')
mana: 30
@@ -641,10 +650,10 @@ api.spells =
target: 'party'
notes: t('spellHealerProtectAuraNotes')
cast: (user, target) ->
## lasts 24 hours ##
_.each target, (member) ->
bonus = user._statsComputed.con
member.stats.buffs.con ?= 0
member.stats.buffs.con += Math.ceil(user._statsComputed.con * .15)
member.stats.buffs.con += Math.ceil(diminishingReturns(bonus, 200, 200))
heallAll:
text: t('spellHealerHealAllText')
mana: 25
@@ -825,11 +834,11 @@ api.specialPets =
'Mammoth-Base': 'mammoth'
api.specialMounts =
'BearCub-Polar': 'polarBear'
'LionCub-Ethereal': 'etherealLion'
'MantisShrimp-Base': 'mantisShrimp'
'Turkey-Base': 'turkey'
'Mammoth-Base': 'mammoth'
'BearCub-Polar': 'polarBear'
'LionCub-Ethereal': 'etherealLion'
'MantisShrimp-Base': 'mantisShrimp'
'Turkey-Base': 'turkey'
'Mammoth-Base': 'mammoth'
api.hatchingPotions =
Base: value: 2, text: t('hatchingPotionBase')
@@ -1043,7 +1052,7 @@ api.quests =
]
gp: 25
exp: 125
hedgehog:
text: t('questHedgehogText')
notes: t('questHedgehogNotes')
+40 -17
View File
@@ -1067,12 +1067,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)
# Note, we create a new val (adjustAmt) to add to task.value, since delta will be used in Exp & GP calculations - we don't want STR to bonus that
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 +1111,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 +1140,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 +1167,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 +1224,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
###
@@ -1487,17 +1491,22 @@ 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
return if (type is 'daily') && !completed && user.stats.buffs.stealth && user.stats.buffs.stealth-- # User "evades" a certain number of uncompleted dailies (includes uncompletd GREY dailies - TODO fix that?)
# All processing of Dailies is calculated AFTER stealth -- stealthed Dailies are treated as just not being there
# Deduct experience for missed Daily tasks, but not for Todos (just increase todo's value)
unless completed
# Deduct points for missed Daily tasks, but not for Todos (just increase todo's value)
if completed
if type is 'daily'
dailyChecked += 1
else
scheduleMisses = daysMissed
# 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
@@ -1506,9 +1515,17 @@ api.wrap = (user, main=true) ->
thatDay = moment(now).subtract({days: n + 1})
scheduleMisses++ if api.shouldDo(thatDay, repeat, user.preferences)
if scheduleMisses > 0
perfect = false if type is 'daily'
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, cron:true}});
user.party.quest.progress.down += delta if type is 'daily'
switch type
when 'daily'
@@ -1557,7 +1574,13 @@ api.wrap = (user, main=true) ->
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
#console.log("Prior MP: " + user.stats.mp)
dailyChecked=1 if dailyDueUnchecked is 0 and dailyChecked is 0
#console.log("DueUnchecked: " + dailyDueUnchecked)
#console.log("Checked: " + dailyChecked)
user.stats.mp += _.max([10,.1 * user._statsComputed.maxMP]) * dailyChecked / (dailyDueUnchecked + dailyChecked)
#console.log("After MP: " +user.stats.mp)
user.stats.mp = user._statsComputed.maxMP if user.stats.mp > user._statsComputed.maxMP
# After all is said and done, progress up user's effect on quest, return those values & reset the user's
+1
View File
File diff suppressed because one or more lines are too long