mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-17 14:47:53 +01:00
Convert common tests to js
This commit is contained in:
@@ -1,925 +0,0 @@
|
|||||||
_ = require 'lodash'
|
|
||||||
expect = require 'expect.js'
|
|
||||||
sinon = require 'sinon'
|
|
||||||
moment = require 'moment'
|
|
||||||
shared = require '../../common/script/index.js'
|
|
||||||
shared.i18n.translations = require('../../website/src/libs/i18n.js').translations
|
|
||||||
test_helper = require './test_helper'
|
|
||||||
test_helper.addCustomMatchers()
|
|
||||||
$w = (s)->s.split(' ')
|
|
||||||
|
|
||||||
### Helper Functions ####
|
|
||||||
newUser = (addTasks=true)->
|
|
||||||
buffs = {per:0, int:0, con:0, str:0, stealth: 0, streaks: false}
|
|
||||||
user =
|
|
||||||
auth:
|
|
||||||
timestamps: {}
|
|
||||||
stats: {str:1, con:1, per:1, int:1, mp: 32, class: 'warrior', buffs: buffs}
|
|
||||||
items:
|
|
||||||
lastDrop:
|
|
||||||
count: 0
|
|
||||||
hatchingPotions: {}
|
|
||||||
eggs: {}
|
|
||||||
food: {}
|
|
||||||
gear:
|
|
||||||
equipped: {}
|
|
||||||
costume: {}
|
|
||||||
owned: {}
|
|
||||||
quests: {}
|
|
||||||
party:
|
|
||||||
quest:
|
|
||||||
progress:
|
|
||||||
down: 0
|
|
||||||
preferences: {
|
|
||||||
autoEquip: true
|
|
||||||
}
|
|
||||||
dailys: []
|
|
||||||
todos: []
|
|
||||||
rewards: []
|
|
||||||
flags: {}
|
|
||||||
achievements:
|
|
||||||
ultimateGearSets: {}
|
|
||||||
contributor:
|
|
||||||
level: 2
|
|
||||||
_tmp: {}
|
|
||||||
|
|
||||||
shared.wrap(user)
|
|
||||||
user.ops.reset(null, ->)
|
|
||||||
if addTasks
|
|
||||||
_.each ['habit', 'todo', 'daily'], (task)->
|
|
||||||
user.ops.addTask {body: {type: task, id: shared.uuid()}}
|
|
||||||
user
|
|
||||||
|
|
||||||
rewrapUser = (user)->
|
|
||||||
user._wrapped = false
|
|
||||||
shared.wrap(user)
|
|
||||||
user
|
|
||||||
|
|
||||||
expectStrings = (obj, paths) ->
|
|
||||||
_.each paths, (path) -> expect(obj[path]).to.be.ok()
|
|
||||||
|
|
||||||
# options.daysAgo: days ago when the last cron was executed
|
|
||||||
# cronAfterStart: moves the lastCron to be after the dayStart.
|
|
||||||
# This way the daysAgo works as expected if the test case
|
|
||||||
# makes the assumption that the lastCron was after dayStart.
|
|
||||||
beforeAfter = (options={}) ->
|
|
||||||
user = newUser()
|
|
||||||
[before, after] = [user, _.cloneDeep(user)]
|
|
||||||
# avoid closure on the original user
|
|
||||||
rewrapUser(after)
|
|
||||||
before.preferences.dayStart = after.preferences.dayStart = options.dayStart if options.dayStart
|
|
||||||
before.preferences.timezoneOffset = after.preferences.timezoneOffset = (options.timezoneOffset or moment().zone())
|
|
||||||
if options.limitOne
|
|
||||||
before["#{options.limitOne}s"] = [before["#{options.limitOne}s"][0]]
|
|
||||||
after["#{options.limitOne}s"] = [after["#{options.limitOne}s"][0]]
|
|
||||||
lastCron = moment(options.now || +new Date).subtract( {days:options.daysAgo} ) if options.daysAgo
|
|
||||||
lastCron.add( {hours:options.dayStart, minutes:1} ) if options.daysAgo and options.cronAfterStart
|
|
||||||
lastCron = +lastCron if options.daysAgo
|
|
||||||
_.each [before,after], (obj) ->
|
|
||||||
obj.lastCron = lastCron if options.daysAgo
|
|
||||||
{before:before, after:after}
|
|
||||||
#TODO calculate actual points
|
|
||||||
|
|
||||||
expectLostPoints = (before, after, taskType) ->
|
|
||||||
if taskType in ['daily','habit']
|
|
||||||
expect(after.stats.hp).to.be.lessThan before.stats.hp
|
|
||||||
expect(after["#{taskType}s"][0].history).to.have.length(1)
|
|
||||||
else expect(after.history.todos).to.have.length(1)
|
|
||||||
expect(after).toHaveExp 0
|
|
||||||
expect(after).toHaveGP 0
|
|
||||||
expect(after["#{taskType}s"][0].value).to.be.lessThan before["#{taskType}s"][0].value
|
|
||||||
|
|
||||||
expectGainedPoints = (before, after, taskType) ->
|
|
||||||
expect(after.stats.hp).to.be 50
|
|
||||||
expect(after.stats.exp).to.be.greaterThan before.stats.exp
|
|
||||||
expect(after.stats.gp).to.be.greaterThan before.stats.gp
|
|
||||||
expect(after["#{taskType}s"][0].value).to.be.greaterThan before["#{taskType}s"][0].value
|
|
||||||
expect(after["#{taskType}s"][0].history).to.have.length(1) if taskType is 'habit'
|
|
||||||
# daily & todo histories handled on cron
|
|
||||||
|
|
||||||
expectNoChange = (before,after) ->
|
|
||||||
_.each $w('stats items gear dailys todos rewards 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) ->
|
|
||||||
expect(task.completed).to.be false
|
|
||||||
expect(before.dailys[i].value).to.be task.value
|
|
||||||
expect(before.dailys[i].streak).to.be task.streak
|
|
||||||
expect(task.history).to.have.length(1)
|
|
||||||
_.each after.todos, (task,i) ->
|
|
||||||
expect(task.completed).to.be false
|
|
||||||
expect(before.todos[i].value).to.be.greaterThan task.value
|
|
||||||
expect(after.history.todos).to.have.length(1)
|
|
||||||
# hack so we can compare user before/after obj equality sans effected paths
|
|
||||||
_.each [before,after], (obj) ->
|
|
||||||
delete obj.stats.buffs
|
|
||||||
_.each $w('dailys todos history lastCron'), (path) -> delete obj[path]
|
|
||||||
delete after._tmp
|
|
||||||
expectNoChange(before, after)
|
|
||||||
|
|
||||||
cycle = (array)->
|
|
||||||
n = -1
|
|
||||||
(seed=0)->
|
|
||||||
n++
|
|
||||||
return array[n % array.length]
|
|
||||||
|
|
||||||
repeatWithoutLastWeekday = ()->
|
|
||||||
repeat = {su:true,m:true,t:true,w:true,th:true,f:true,s:true}
|
|
||||||
if shared.startOfWeek(moment().zone(0)).isoWeekday() == 1 # Monday
|
|
||||||
repeat.su = false
|
|
||||||
else
|
|
||||||
repeat.s = false
|
|
||||||
{repeat: repeat}
|
|
||||||
|
|
||||||
###### Specs ######
|
|
||||||
|
|
||||||
describe 'User', ->
|
|
||||||
it 'sets correct user defaults', ->
|
|
||||||
user = newUser()
|
|
||||||
base_gear = { armor: 'armor_base_0', weapon: 'weapon_base_0', head: 'head_base_0', shield: 'shield_base_0' }
|
|
||||||
buffs = {per:0, int:0, con:0, str:0, stealth: 0, streaks: false}
|
|
||||||
expect(user.stats).to.eql { str: 1, con: 1, per: 1, int: 1, hp: 50, mp: 32, lvl: 1, exp: 0, gp: 0, class: 'warrior', buffs: buffs }
|
|
||||||
expect(user.items.gear).to.eql { equipped: base_gear, costume: base_gear, owned: {weapon_warrior_0: true} }
|
|
||||||
expect(user.preferences).to.eql { autoEquip: true, costume: false }
|
|
||||||
|
|
||||||
it 'calculates max MP', ->
|
|
||||||
user = newUser()
|
|
||||||
expect(user).toHaveMaxMP 32
|
|
||||||
user.stats.int = 10
|
|
||||||
expect(user).toHaveMaxMP 50
|
|
||||||
user.stats.lvl = 5
|
|
||||||
expect(user).toHaveMaxMP 54
|
|
||||||
user.stats.class = 'wizard'
|
|
||||||
user.items.gear.equipped.weapon = 'weapon_wizard_1'
|
|
||||||
expect(user).toHaveMaxMP 63
|
|
||||||
|
|
||||||
it 'handles perfect days', ->
|
|
||||||
user = newUser()
|
|
||||||
user.dailys = []
|
|
||||||
_.times 3, ->user.dailys.push shared.taskDefaults({type:'daily', startDate: moment().subtract(7, 'days')})
|
|
||||||
cron = -> user.lastCron = moment().subtract(1,'days');user.fns.cron()
|
|
||||||
|
|
||||||
cron()
|
|
||||||
expect(user.stats.buffs.str).to.be 0
|
|
||||||
expect(user.achievements.perfect).to.not.be.ok()
|
|
||||||
|
|
||||||
user.dailys[0].completed = true
|
|
||||||
cron()
|
|
||||||
expect(user.stats.buffs.str).to.be 0
|
|
||||||
expect(user.achievements.perfect).to.not.be.ok()
|
|
||||||
|
|
||||||
_.each user.dailys, (d)->d.completed = true
|
|
||||||
cron()
|
|
||||||
expect(user.stats.buffs.str).to.be 1
|
|
||||||
expect(user.achievements.perfect).to.be 1
|
|
||||||
|
|
||||||
# Handle greyed-out dailys
|
|
||||||
yesterday = moment().subtract(1,'days')
|
|
||||||
user.dailys[0].repeat[shared.dayMapping[yesterday.day()]] = false
|
|
||||||
_.each user.dailys[1..], (d)->d.completed = true
|
|
||||||
cron()
|
|
||||||
expect(user.stats.buffs.str).to.be 1
|
|
||||||
expect(user.achievements.perfect).to.be 2
|
|
||||||
|
|
||||||
describe 'Resting in the Inn', ->
|
|
||||||
user = null
|
|
||||||
cron = null
|
|
||||||
|
|
||||||
beforeEach ->
|
|
||||||
user = newUser()
|
|
||||||
user.preferences.sleep = true
|
|
||||||
cron = -> user.lastCron = moment().subtract(1, 'days');user.fns.cron()
|
|
||||||
user.dailys = []
|
|
||||||
_.times 2, -> user.dailys.push shared.taskDefaults({type:'daily', startDate: moment().subtract(7, 'days')})
|
|
||||||
|
|
||||||
it 'remains in the inn on cron', ->
|
|
||||||
cron()
|
|
||||||
expect(user.preferences.sleep).to.be true
|
|
||||||
|
|
||||||
it 'resets dailies', ->
|
|
||||||
user.dailys[0].completed = true
|
|
||||||
cron()
|
|
||||||
expect(user.dailys[0].completed).to.be false
|
|
||||||
|
|
||||||
it 'resets checklist on incomplete dailies', ->
|
|
||||||
user.dailys[0].checklist = [
|
|
||||||
{
|
|
||||||
"text" : "1",
|
|
||||||
"id" : "checklist-one",
|
|
||||||
"completed" : true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"text" : "2",
|
|
||||||
"id" : "checklist-two",
|
|
||||||
"completed" : true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"text" : "3",
|
|
||||||
"id" : "checklist-three",
|
|
||||||
"completed" : false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
cron()
|
|
||||||
_.each user.dailys[0].checklist, (box)->
|
|
||||||
expect(box.completed).to.be false
|
|
||||||
|
|
||||||
it 'resets checklist on complete dailies', ->
|
|
||||||
user.dailys[0].checklist = [
|
|
||||||
{
|
|
||||||
"text" : "1",
|
|
||||||
"id" : "checklist-one",
|
|
||||||
"completed" : true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"text" : "2",
|
|
||||||
"id" : "checklist-two",
|
|
||||||
"completed" : true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"text" : "3",
|
|
||||||
"id" : "checklist-three",
|
|
||||||
"completed" : false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
user.dailys[0].completed = true
|
|
||||||
cron()
|
|
||||||
_.each user.dailys[0].checklist, (box)->
|
|
||||||
expect(box.completed).to.be false
|
|
||||||
|
|
||||||
it 'does not reset checklist on grey incomplete dailies', ->
|
|
||||||
yesterday = moment().subtract(1,'days')
|
|
||||||
user.dailys[0].repeat[shared.dayMapping[yesterday.day()]] = false
|
|
||||||
user.dailys[0].checklist = [
|
|
||||||
{
|
|
||||||
"text" : "1",
|
|
||||||
"id" : "checklist-one",
|
|
||||||
"completed" : true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"text" : "2",
|
|
||||||
"id" : "checklist-two",
|
|
||||||
"completed" : true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"text" : "3",
|
|
||||||
"id" : "checklist-three",
|
|
||||||
"completed" : true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
cron()
|
|
||||||
_.each user.dailys[0].checklist, (box)->
|
|
||||||
expect(box.completed).to.be true
|
|
||||||
|
|
||||||
it 'resets checklist on complete grey complete dailies', ->
|
|
||||||
yesterday = moment().subtract(1,'days')
|
|
||||||
user.dailys[0].repeat[shared.dayMapping[yesterday.day()]] = false
|
|
||||||
user.dailys[0].checklist = [
|
|
||||||
{
|
|
||||||
"text" : "1",
|
|
||||||
"id" : "checklist-one",
|
|
||||||
"completed" : true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"text" : "2",
|
|
||||||
"id" : "checklist-two",
|
|
||||||
"completed" : true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"text" : "3",
|
|
||||||
"id" : "checklist-three",
|
|
||||||
"completed" : true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
user.dailys[0].completed = true
|
|
||||||
|
|
||||||
cron()
|
|
||||||
_.each user.dailys[0].checklist, (box)->
|
|
||||||
expect(box.completed).to.be false
|
|
||||||
|
|
||||||
it 'does not damage user for incomplete dailies', ->
|
|
||||||
expect(user).toHaveHP 50
|
|
||||||
user.dailys[0].completed = true
|
|
||||||
user.dailys[1].completed = false
|
|
||||||
cron()
|
|
||||||
expect(user).toHaveHP 50
|
|
||||||
|
|
||||||
it 'gives credit for complete dailies', ->
|
|
||||||
user.dailys[0].completed = true
|
|
||||||
expect(user.dailys[0].history).to.be.empty
|
|
||||||
cron()
|
|
||||||
expect(user.dailys[0].history).to.not.be.empty
|
|
||||||
|
|
||||||
it 'damages user for incomplete dailies after checkout', ->
|
|
||||||
expect(user).toHaveHP 50
|
|
||||||
user.dailys[0].completed = true
|
|
||||||
user.dailys[1].completed = false
|
|
||||||
user.preferences.sleep = false
|
|
||||||
cron()
|
|
||||||
expect(user.stats.hp).to.be.lessThan 50
|
|
||||||
|
|
||||||
describe 'Death', ->
|
|
||||||
user = undefined
|
|
||||||
it 'revives correctly', ->
|
|
||||||
user = newUser()
|
|
||||||
user.stats = { gp: 10, exp: 100, lvl: 2, hp: 0, class: 'warrior' }
|
|
||||||
user.ops.revive()
|
|
||||||
expect(user).toHaveGP 0
|
|
||||||
expect(user).toHaveExp 0
|
|
||||||
expect(user).toHaveLevel 1
|
|
||||||
expect(user).toHaveHP 50
|
|
||||||
expect(user.items.gear.owned).to.eql { weapon_warrior_0: false }
|
|
||||||
|
|
||||||
it "doesn't break unbreakables", ->
|
|
||||||
ce = shared.countExists
|
|
||||||
user = newUser()
|
|
||||||
# breakables (includes default weapon_warrior_0):
|
|
||||||
user.items.gear.owned['shield_warrior_1'] = true
|
|
||||||
# unbreakables because off-class or 0 value:
|
|
||||||
user.items.gear.owned['shield_rogue_1'] = true
|
|
||||||
user.items.gear.owned['head_special_nye'] = true
|
|
||||||
expect(ce user.items.gear.owned).to.be 4
|
|
||||||
user.stats.hp = 0
|
|
||||||
user.ops.revive()
|
|
||||||
expect(ce(user.items.gear.owned)).to.be 3
|
|
||||||
user.stats.hp = 0
|
|
||||||
user.ops.revive()
|
|
||||||
expect(ce(user.items.gear.owned)).to.be 2
|
|
||||||
user.stats.hp = 0
|
|
||||||
user.ops.revive()
|
|
||||||
expect(ce(user.items.gear.owned)).to.be 2
|
|
||||||
expect(user.items.gear.owned).to.eql { weapon_warrior_0: false, shield_warrior_1: false, shield_rogue_1: true, head_special_nye: true }
|
|
||||||
|
|
||||||
it "handles event items", ->
|
|
||||||
shared.content.gear.flat.head_special_nye.event.start = '2012-01-01'
|
|
||||||
shared.content.gear.flat.head_special_nye.event.end = '2012-02-01'
|
|
||||||
expect(shared.content.gear.flat.head_special_nye.canOwn(user)).to.be true
|
|
||||||
delete user.items.gear.owned['head_special_nye']
|
|
||||||
expect(shared.content.gear.flat.head_special_nye.canOwn(user)).to.be false
|
|
||||||
|
|
||||||
shared.content.gear.flat.head_special_nye.event.start = moment().subtract(5,'days')
|
|
||||||
shared.content.gear.flat.head_special_nye.event.end = moment().add(5,'days')
|
|
||||||
expect(shared.content.gear.flat.head_special_nye.canOwn(user)).to.be true
|
|
||||||
|
|
||||||
describe 'Rebirth', ->
|
|
||||||
user = undefined
|
|
||||||
it 'removes correct gear', ->
|
|
||||||
user = newUser()
|
|
||||||
user.stats.lvl = 100
|
|
||||||
user.items.gear.owned = {
|
|
||||||
"weapon_warrior_0": true,
|
|
||||||
"weapon_warrior_1": true,
|
|
||||||
"armor_warrior_1": false,
|
|
||||||
"armor_mystery_201402": true,
|
|
||||||
"back_mystery_201402": false,
|
|
||||||
"head_mystery_201402": true,
|
|
||||||
"weapon_armoire_basicCrossbow": true,
|
|
||||||
}
|
|
||||||
user.ops.rebirth()
|
|
||||||
expect(user.items.gear.owned).to.eql {
|
|
||||||
"weapon_warrior_0": true,
|
|
||||||
"weapon_warrior_1": false,
|
|
||||||
"armor_warrior_1": false,
|
|
||||||
"armor_mystery_201402": true,
|
|
||||||
"back_mystery_201402": false,
|
|
||||||
"head_mystery_201402": true,
|
|
||||||
"weapon_armoire_basicCrossbow": false,
|
|
||||||
}
|
|
||||||
|
|
||||||
describe 'store', ->
|
|
||||||
it 'buys a Quest scroll', ->
|
|
||||||
user = newUser()
|
|
||||||
user.stats.gp = 205
|
|
||||||
user.ops.buyQuest {params: {key: 'dilatoryDistress1'}}
|
|
||||||
expect(user.items.quests).to.eql {dilatoryDistress1: 1}
|
|
||||||
expect(user).toHaveGP 5
|
|
||||||
|
|
||||||
it 'does not buy Quests without enough Gold', ->
|
|
||||||
user = newUser()
|
|
||||||
user.stats.gp = 1
|
|
||||||
user.ops.buyQuest {params: {key: 'dilatoryDistress1'}}
|
|
||||||
expect(user.items.quests).to.eql {}
|
|
||||||
expect(user).toHaveGP 1
|
|
||||||
|
|
||||||
it 'does not buy nonexistent Quests', ->
|
|
||||||
user = newUser()
|
|
||||||
user.stats.gp = 9999
|
|
||||||
user.ops.buyQuest {params: {key: 'snarfblatter'}}
|
|
||||||
expect(user.items.quests).to.eql {}
|
|
||||||
expect(user).toHaveGP 9999
|
|
||||||
|
|
||||||
it 'does not buy Gem-premium Quests', ->
|
|
||||||
user = newUser()
|
|
||||||
user.stats.gp = 9999
|
|
||||||
user.ops.buyQuest {params: {key: 'kraken'}}
|
|
||||||
expect(user.items.quests).to.eql {}
|
|
||||||
expect(user).toHaveGP 9999
|
|
||||||
|
|
||||||
describe 'Gem purchases', ->
|
|
||||||
it 'does not purchase items without enough Gems', ->
|
|
||||||
user = newUser()
|
|
||||||
user.ops.purchase {params: {type: 'eggs', key: 'Cactus'}}
|
|
||||||
user.ops.purchase {params: {type: 'gear', key: 'headAccessory_special_foxEars'}}
|
|
||||||
user.ops.unlock {query: {path: 'items.gear.owned.headAccessory_special_bearEars,items.gear.owned.headAccessory_special_cactusEars,items.gear.owned.headAccessory_special_foxEars,items.gear.owned.headAccessory_special_lionEars,items.gear.owned.headAccessory_special_pandaEars,items.gear.owned.headAccessory_special_pigEars,items.gear.owned.headAccessory_special_tigerEars,items.gear.owned.headAccessory_special_wolfEars'}}
|
|
||||||
expect(user.items.eggs).to.eql {}
|
|
||||||
expect(user.items.gear.owned).to.eql { weapon_warrior_0: true }
|
|
||||||
|
|
||||||
it 'purchases an egg', ->
|
|
||||||
user = newUser()
|
|
||||||
user.balance = 1
|
|
||||||
user.ops.purchase {params: {type: 'eggs', key: 'Cactus'}}
|
|
||||||
expect(user.items.eggs).to.eql { Cactus: 1}
|
|
||||||
expect(user.balance).to.eql 0.25
|
|
||||||
|
|
||||||
it 'purchases fox ears', ->
|
|
||||||
user = newUser()
|
|
||||||
user.balance = 1
|
|
||||||
user.ops.purchase {params: {type: 'gear', key: 'headAccessory_special_foxEars'}}
|
|
||||||
expect(user.items.gear.owned).to.eql { weapon_warrior_0: true, headAccessory_special_foxEars: true }
|
|
||||||
expect(user.balance).to.eql 0.5
|
|
||||||
|
|
||||||
it 'unlocks all the animal ears at once', ->
|
|
||||||
user = newUser()
|
|
||||||
user.balance = 2
|
|
||||||
user.ops.unlock {query: {path: 'items.gear.owned.headAccessory_special_bearEars,items.gear.owned.headAccessory_special_cactusEars,items.gear.owned.headAccessory_special_foxEars,items.gear.owned.headAccessory_special_lionEars,items.gear.owned.headAccessory_special_pandaEars,items.gear.owned.headAccessory_special_pigEars,items.gear.owned.headAccessory_special_tigerEars,items.gear.owned.headAccessory_special_wolfEars'}}
|
|
||||||
expect(user.items.gear.owned).to.eql { weapon_warrior_0: true, headAccessory_special_bearEars: true, headAccessory_special_cactusEars: true, headAccessory_special_foxEars: true, headAccessory_special_lionEars: true, headAccessory_special_pandaEars: true, headAccessory_special_pigEars: true, headAccessory_special_tigerEars: true, headAccessory_special_wolfEars: true}
|
|
||||||
expect(user.balance).to.eql 0.75
|
|
||||||
|
|
||||||
describe 'spells', ->
|
|
||||||
_.each shared.content.spells, (spellClass)->
|
|
||||||
_.each spellClass, (spell)->
|
|
||||||
it "#{spell.text} has valid values", ->
|
|
||||||
expect(spell.target).to.match(/^(task|self|party|user)$/)
|
|
||||||
expect(spell.mana).to.be.an('number')
|
|
||||||
if spell.lvl
|
|
||||||
expect(spell.lvl).to.be.an('number')
|
|
||||||
expect(spell.lvl).to.be.above(0)
|
|
||||||
expect(spell.cast).to.be.a('function')
|
|
||||||
|
|
||||||
describe 'drop system', ->
|
|
||||||
user = null
|
|
||||||
MIN_RANGE_FOR_POTION = 0
|
|
||||||
MAX_RANGE_FOR_POTION = .3
|
|
||||||
MIN_RANGE_FOR_EGG = .4
|
|
||||||
MAX_RANGE_FOR_EGG = .6
|
|
||||||
MIN_RANGE_FOR_FOOD = .7
|
|
||||||
MAX_RANGE_FOR_FOOD = 1
|
|
||||||
|
|
||||||
beforeEach ->
|
|
||||||
user = newUser()
|
|
||||||
user.flags.dropsEnabled = true
|
|
||||||
@task_id = shared.uuid()
|
|
||||||
user.ops.addTask({body: {type: 'daily', id: @task_id}})
|
|
||||||
|
|
||||||
it 'drops a hatching potion', ->
|
|
||||||
for random in [MIN_RANGE_FOR_POTION..MAX_RANGE_FOR_POTION] by .1
|
|
||||||
sinon.stub(user.fns, 'predictableRandom').returns random
|
|
||||||
user.ops.score {params: { id: @task_id, direction: 'up'}}
|
|
||||||
expect(user.items.eggs).to.be.empty
|
|
||||||
expect(user.items.hatchingPotions).to.not.be.empty
|
|
||||||
expect(user.items.food).to.be.empty
|
|
||||||
user.fns.predictableRandom.restore()
|
|
||||||
|
|
||||||
it 'drops a pet egg', ->
|
|
||||||
for random in [MIN_RANGE_FOR_EGG..MAX_RANGE_FOR_EGG] by .1
|
|
||||||
sinon.stub(user.fns, 'predictableRandom').returns random
|
|
||||||
user.ops.score {params: { id: @task_id, direction: 'up'}}
|
|
||||||
expect(user.items.eggs).to.not.be.empty
|
|
||||||
expect(user.items.hatchingPotions).to.be.empty
|
|
||||||
expect(user.items.food).to.be.empty
|
|
||||||
user.fns.predictableRandom.restore()
|
|
||||||
|
|
||||||
it 'drops food', ->
|
|
||||||
for random in [MIN_RANGE_FOR_FOOD..MAX_RANGE_FOR_FOOD] by .1
|
|
||||||
sinon.stub(user.fns, 'predictableRandom').returns random
|
|
||||||
user.ops.score {params: { id: @task_id, direction: 'up'}}
|
|
||||||
expect(user.items.eggs).to.be.empty
|
|
||||||
expect(user.items.hatchingPotions).to.be.empty
|
|
||||||
expect(user.items.food).to.not.be.empty
|
|
||||||
user.fns.predictableRandom.restore()
|
|
||||||
|
|
||||||
it 'does not get a drop', ->
|
|
||||||
sinon.stub(user.fns, 'predictableRandom').returns 0.5
|
|
||||||
user.ops.score {params: { id: @task_id, direction: 'up'}}
|
|
||||||
expect(user.items.eggs).to.eql {}
|
|
||||||
expect(user.items.hatchingPotions).to.eql {}
|
|
||||||
expect(user.items.food).to.eql {}
|
|
||||||
user.fns.predictableRandom.restore()
|
|
||||||
|
|
||||||
describe 'Quests', ->
|
|
||||||
_.each shared.content.quests, (quest)->
|
|
||||||
it "#{quest.text()} has valid values", ->
|
|
||||||
expect(quest.notes()).to.be.an('string')
|
|
||||||
expect(quest.completion()).to.be.an('string') if quest.completion
|
|
||||||
expect(quest.previous).to.be.an('string') if quest.previous
|
|
||||||
expect(quest.value).to.be.greaterThan 0 if quest.canBuy()
|
|
||||||
expect(quest.drop.gp).to.not.be.lessThan 0
|
|
||||||
expect(quest.drop.exp).to.not.be.lessThan 0
|
|
||||||
expect(quest.category).to.match(/pet|unlockable|gold|world/)
|
|
||||||
if quest.drop.items
|
|
||||||
expect(quest.drop.items).to.be.an(Array)
|
|
||||||
if quest.boss
|
|
||||||
expect(quest.boss.name()).to.be.an('string')
|
|
||||||
expect(quest.boss.hp).to.be.greaterThan 0
|
|
||||||
expect(quest.boss.str).to.be.greaterThan 0
|
|
||||||
else if quest.collect
|
|
||||||
_.each quest.collect, (collect)->
|
|
||||||
expect(collect.text()).to.be.an('string')
|
|
||||||
expect(collect.count).to.be.greaterThan 0
|
|
||||||
|
|
||||||
describe 'Achievements', ->
|
|
||||||
_.each shared.content.classes, (klass) ->
|
|
||||||
user = newUser()
|
|
||||||
user.stats.gp = 10000
|
|
||||||
_.each shared.content.gearTypes, (type) ->
|
|
||||||
_.each [1..5], (i) ->
|
|
||||||
user.ops.buy {params:'#{type}_#{klass}_#{i}'}
|
|
||||||
it 'does not get ultimateGear ' + klass, ->
|
|
||||||
expect(user.achievements.ultimateGearSets[klass]).to.not.be.ok()
|
|
||||||
_.each shared.content.gearTypes, (type) ->
|
|
||||||
user.ops.buy {params:'#{type}_#{klass}_6'}
|
|
||||||
xit 'gets ultimateGear ' + klass, ->
|
|
||||||
expect(user.achievements.ultimateGearSets[klass]).to.be.ok()
|
|
||||||
|
|
||||||
it 'does not remove existing Ultimate Gear achievements', ->
|
|
||||||
user = newUser()
|
|
||||||
user.achievements.ultimateGearSets = {'healer':true,'wizard':true,'rogue':true,'warrior':true}
|
|
||||||
user.items.gear.owned.shield_warrior_5 = false
|
|
||||||
user.items.gear.owned.weapon_rogue_6 = false
|
|
||||||
user.ops.buy {params:'shield_warrior_5'}
|
|
||||||
expect(user.achievements.ultimateGearSets).to.eql {'healer':true,'wizard':true,'rogue':true,'warrior':true}
|
|
||||||
|
|
||||||
describe 'unlocking features', ->
|
|
||||||
it 'unlocks drops at level 3', ->
|
|
||||||
user = newUser()
|
|
||||||
user.stats.lvl = 3
|
|
||||||
user.fns.updateStats(user.stats)
|
|
||||||
expect(user.flags.dropsEnabled).to.be.ok()
|
|
||||||
|
|
||||||
it 'unlocks Rebirth at level 50', ->
|
|
||||||
user = newUser()
|
|
||||||
user.stats.lvl = 50
|
|
||||||
user.fns.updateStats(user.stats)
|
|
||||||
expect(user.flags.rebirthEnabled).to.be.ok()
|
|
||||||
|
|
||||||
describe 'level-awarded Quests', ->
|
|
||||||
it 'gets Attack of the Mundane at level 15', ->
|
|
||||||
user = newUser()
|
|
||||||
user.stats.lvl = 15
|
|
||||||
user.fns.updateStats(user.stats)
|
|
||||||
expect(user.flags.levelDrops.atom1).to.be.ok()
|
|
||||||
expect(user.items.quests.atom1).to.eql 1
|
|
||||||
|
|
||||||
it 'gets Vice at level 30', ->
|
|
||||||
user = newUser()
|
|
||||||
user.stats.lvl = 30
|
|
||||||
user.fns.updateStats(user.stats)
|
|
||||||
expect(user.flags.levelDrops.vice1).to.be.ok()
|
|
||||||
expect(user.items.quests.vice1).to.eql 1
|
|
||||||
|
|
||||||
it 'gets Golden Knight at level 40', ->
|
|
||||||
user = newUser()
|
|
||||||
user.stats.lvl = 40
|
|
||||||
user.fns.updateStats(user.stats)
|
|
||||||
expect(user.flags.levelDrops.goldenknight1).to.be.ok()
|
|
||||||
expect(user.items.quests.goldenknight1).to.eql 1
|
|
||||||
|
|
||||||
it 'gets Moonstone Chain at level 60', ->
|
|
||||||
user = newUser()
|
|
||||||
user.stats.lvl = 60
|
|
||||||
user.fns.updateStats(user.stats)
|
|
||||||
expect(user.flags.levelDrops.moonstone1).to.be.ok()
|
|
||||||
expect(user.items.quests.moonstone1).to.eql 1
|
|
||||||
|
|
||||||
describe 'Simple Scoring', ->
|
|
||||||
beforeEach ->
|
|
||||||
{@before, @after} = beforeAfter()
|
|
||||||
|
|
||||||
it 'Habits : Up', ->
|
|
||||||
@after.ops.score {params: {id: @after.habits[0].id, direction: 'down'}, query: {times: 5}}
|
|
||||||
expectLostPoints(@before, @after,'habit')
|
|
||||||
|
|
||||||
it 'Habits : Down', ->
|
|
||||||
@after.ops.score {params: {id: @after.habits[0].id, direction: 'up'}, query: {times: 5}}
|
|
||||||
expectGainedPoints(@before, @after,'habit')
|
|
||||||
|
|
||||||
it 'Dailys : Up', ->
|
|
||||||
@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', ->
|
|
||||||
user = newUser()
|
|
||||||
|
|
||||||
paths = {};user.fns.cron {paths}
|
|
||||||
expect(user.lastCron).to.not.be.ok # it setup the cron property now
|
|
||||||
|
|
||||||
user.lastCron = +moment().subtract(1,'days')
|
|
||||||
|
|
||||||
paths = {};user.fns.cron {paths}
|
|
||||||
expect(user.lastCron).to.be.greaterThan 0
|
|
||||||
|
|
||||||
# user.lastCron = +moment().add(1,'days')
|
|
||||||
# paths = {};algos.cron user, {paths}
|
|
||||||
# expect(paths.lastCron).to.be true # busted cron (was set to after today's date)
|
|
||||||
|
|
||||||
it 'only dailies & todos are affected', ->
|
|
||||||
{before,after} = beforeAfter({daysAgo:1})
|
|
||||||
before.dailys = before.todos = after.dailys = after.todos = []
|
|
||||||
after.fns.cron()
|
|
||||||
before.stats.mp=after.stats.mp #FIXME
|
|
||||||
expect(after.lastCron).to.not.be before.lastCron # make sure cron was run
|
|
||||||
delete after.stats.buffs;delete before.stats.buffs
|
|
||||||
expect(before.stats).to.eql after.stats
|
|
||||||
beforeTasks = before.habits.concat(before.dailys).concat(before.todos).concat(before.rewards)
|
|
||||||
afterTasks = after.habits.concat(after.dailys).concat(after.todos).concat(after.rewards)
|
|
||||||
expect(beforeTasks).to.eql afterTasks
|
|
||||||
|
|
||||||
describe 'preening', ->
|
|
||||||
beforeEach ->
|
|
||||||
@clock = sinon.useFakeTimers(Date.parse("2013-11-20"), "Date")
|
|
||||||
|
|
||||||
afterEach ->
|
|
||||||
@clock.restore()
|
|
||||||
|
|
||||||
it 'should preen user history', ->
|
|
||||||
{before,after} = beforeAfter({daysAgo:1})
|
|
||||||
history = [
|
|
||||||
# Last year should be condensed to one entry, avg: 1
|
|
||||||
{date:'09/01/2012', value: 0}
|
|
||||||
{date:'10/01/2012', value: 0}
|
|
||||||
{date:'11/01/2012', value: 2}
|
|
||||||
{date:'12/01/2012', value: 2}
|
|
||||||
|
|
||||||
# Each month of this year should be condensed to 1/mo, averages follow
|
|
||||||
{date:'01/01/2013', value: 1} #2
|
|
||||||
{date:'01/15/2013', value: 3}
|
|
||||||
|
|
||||||
{date:'02/01/2013', value: 2} #3
|
|
||||||
{date:'02/15/2013', value: 4}
|
|
||||||
|
|
||||||
{date:'03/01/2013', value: 3} #4
|
|
||||||
{date:'03/15/2013', value: 5}
|
|
||||||
|
|
||||||
{date:'04/01/2013', value: 4} #5
|
|
||||||
{date:'04/15/2013', value: 6}
|
|
||||||
|
|
||||||
{date:'05/01/2013', value: 5} #6
|
|
||||||
{date:'05/15/2013', value: 7}
|
|
||||||
|
|
||||||
{date:'06/01/2013', value: 6} #7
|
|
||||||
{date:'06/15/2013', value: 8}
|
|
||||||
|
|
||||||
{date:'07/01/2013', value: 7} #8
|
|
||||||
{date:'07/15/2013', value: 9}
|
|
||||||
|
|
||||||
{date:'08/01/2013', value: 8} #9
|
|
||||||
{date:'08/15/2013', value: 10}
|
|
||||||
|
|
||||||
{date:'09/01/2013', value: 9} #10
|
|
||||||
{date:'09/15/2013', value: 11}
|
|
||||||
|
|
||||||
{date:'010/01/2013', value: 10} #11
|
|
||||||
{date:'010/15/2013', value: 12}
|
|
||||||
|
|
||||||
# This month should condense each week
|
|
||||||
{date:'011/01/2013', value: 12}
|
|
||||||
{date:'011/02/2013', value: 13}
|
|
||||||
{date:'011/03/2013', value: 14}
|
|
||||||
{date:'011/04/2013', value: 15}
|
|
||||||
]
|
|
||||||
after.history = {exp: _.cloneDeep(history), todos: _.cloneDeep(history)}
|
|
||||||
after.habits[0].history = _.cloneDeep(history)
|
|
||||||
after.fns.cron()
|
|
||||||
|
|
||||||
# remove history entries created by cron
|
|
||||||
after.history.exp.pop()
|
|
||||||
after.history.todos.pop()
|
|
||||||
|
|
||||||
_.each [after.history.exp, after.history.todos, after.habits[0].history], (arr) ->
|
|
||||||
expect(_.map(arr, (x)->x.value)).to.eql [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
|
|
||||||
|
|
||||||
describe 'Todos', ->
|
|
||||||
it '1 day missed', ->
|
|
||||||
{before,after} = beforeAfter({daysAgo:1})
|
|
||||||
before.dailys = after.dailys = []
|
|
||||||
after.fns.cron()
|
|
||||||
|
|
||||||
# todos don't effect stats
|
|
||||||
expect(after).toHaveHP 50
|
|
||||||
expect(after).toHaveExp 0
|
|
||||||
expect(after).toHaveGP 0
|
|
||||||
|
|
||||||
# but they devalue
|
|
||||||
expect(before.todos[0].value).to.be 0 # sanity check for task setup
|
|
||||||
expect(after.todos[0].value).to.be -1 # the actual test
|
|
||||||
expect(after.history.todos).to.have.length 1
|
|
||||||
|
|
||||||
it '2 days missed', ->
|
|
||||||
{before,after} = beforeAfter({daysAgo:2})
|
|
||||||
before.dailys = after.dailys = []
|
|
||||||
after.fns.cron()
|
|
||||||
|
|
||||||
# todos devalue by only one day's worth of devaluation
|
|
||||||
expect(before.todos[0].value).to.be 0 # sanity check for task setup
|
|
||||||
expect(after.todos[0].value).to.be -1 # the actual test
|
|
||||||
|
|
||||||
# I used hard-coded dates here instead of 'now' so the tests don't fail
|
|
||||||
# when you run them between midnight and dayStart. Nothing worse than
|
|
||||||
# intermittent failures.
|
|
||||||
describe 'cron day calculations', ->
|
|
||||||
dayStart = 4
|
|
||||||
fstr = "YYYY-MM-DD HH:mm:ss"
|
|
||||||
|
|
||||||
it 'startOfDay before dayStart', ->
|
|
||||||
# If the time is before dayStart, then we expect the start of the day to be yesterday at dayStart
|
|
||||||
start = shared.startOfDay {now: moment('2014-10-09 02:30:00'), dayStart}
|
|
||||||
expect(start.format(fstr)).to.eql '2014-10-08 04:00:00'
|
|
||||||
|
|
||||||
it 'startOfDay after dayStart', ->
|
|
||||||
# If the time is after dayStart, then we expect the start of the day to be today at dayStart
|
|
||||||
start = shared.startOfDay {now: moment('2014-10-09 05:30:00'), dayStart}
|
|
||||||
expect(start.format(fstr)).to.eql '2014-10-09 04:00:00'
|
|
||||||
|
|
||||||
it 'daysSince cron before, now after', ->
|
|
||||||
# If the lastCron was before dayStart, then a time on the same day after dayStart
|
|
||||||
# should be 1 day later than lastCron
|
|
||||||
lastCron = moment('2014-10-09 02:30:00')
|
|
||||||
days = shared.daysSince(lastCron, {now: moment('2014-10-09 11:30:00'), dayStart})
|
|
||||||
expect(days).to.eql 1
|
|
||||||
|
|
||||||
it 'daysSince cron before, now before', ->
|
|
||||||
# If the lastCron was before dayStart, then a time on the same day also before dayStart
|
|
||||||
# should be 0 days later than lastCron
|
|
||||||
lastCron = moment('2014-10-09 02:30:00')
|
|
||||||
days = shared.daysSince(lastCron, {now: moment('2014-10-09 03:30:00'), dayStart})
|
|
||||||
expect(days).to.eql 0
|
|
||||||
|
|
||||||
it 'daysSince cron after, now after', ->
|
|
||||||
# If the lastCron was after dayStart, then a time on the same day also after dayStart
|
|
||||||
# should be 0 days later than lastCron
|
|
||||||
lastCron = moment('2014-10-09 05:30:00')
|
|
||||||
days = shared.daysSince(lastCron, {now: moment('2014-10-09 06:30:00'), dayStart})
|
|
||||||
expect(days).to.eql 0
|
|
||||||
|
|
||||||
it 'daysSince cron after, now tomorrow before', ->
|
|
||||||
# If the lastCron was after dayStart, then a time on the following day but before dayStart
|
|
||||||
# should be 0 days later than lastCron
|
|
||||||
lastCron = moment('2014-10-09 12:30:00')
|
|
||||||
days = shared.daysSince(lastCron, {now: moment('2014-10-10 01:30:00'), dayStart})
|
|
||||||
expect(days).to.eql 0
|
|
||||||
|
|
||||||
it 'daysSince cron after, now tomorrow after', ->
|
|
||||||
# If the lastCron was after dayStart, then a time on the following day and after dayStart
|
|
||||||
# should be 1 day later than lastCron
|
|
||||||
lastCron = moment('2014-10-09 12:30:00')
|
|
||||||
days = shared.daysSince(lastCron, {now: moment('2014-10-10 10:30:00'), dayStart})
|
|
||||||
expect(days).to.eql 1
|
|
||||||
|
|
||||||
xit 'daysSince, last cron before new dayStart', ->
|
|
||||||
# If lastCron was after dayStart (at 1am) with dayStart set at 0, changing dayStart to 4am
|
|
||||||
# should not trigger another cron the same day
|
|
||||||
|
|
||||||
# dayStart is 0
|
|
||||||
lastCron = moment('2014-10-09 01:00:00')
|
|
||||||
# dayStart is 4
|
|
||||||
days = shared.daysSince(lastCron, {now: moment('2014-10-09 05:00:00'), dayStart})
|
|
||||||
expect(days).to.eql 0
|
|
||||||
|
|
||||||
describe 'dailies', ->
|
|
||||||
|
|
||||||
describe 'new day', ->
|
|
||||||
|
|
||||||
###
|
|
||||||
This section runs through a "cron matrix" of all permutations (that I can easily account for). It sets
|
|
||||||
task due days, user custom day start, timezoneOffset, etc - then runs cron, jumps to tomorrow and runs cron,
|
|
||||||
and so on - testing each possible outcome along the way
|
|
||||||
###
|
|
||||||
|
|
||||||
runCron = (options) ->
|
|
||||||
_.each [480, 240, 0, -120], (timezoneOffset) -> # test different timezones
|
|
||||||
now = shared.startOfWeek({timezoneOffset}).add(options.currentHour||0, 'hours')
|
|
||||||
{before,after} = beforeAfter({now, timezoneOffset, daysAgo:1, cronAfterStart:options.cronAfterStart||true, dayStart:options.dayStart||0, limitOne:'daily'})
|
|
||||||
before.dailys[0].repeat = after.dailys[0].repeat = options.repeat if options.repeat
|
|
||||||
before.dailys[0].streak = after.dailys[0].streak = 10
|
|
||||||
before.dailys[0].completed = after.dailys[0].completed = true if options.checked
|
|
||||||
before.dailys[0].startDate = after.dailys[0].startDate = moment().subtract(30, 'days')
|
|
||||||
if options.shouldDo
|
|
||||||
expect(shared.shouldDo(now.toDate(), after.dailys[0], {timezoneOffset, dayStart:options.dayStart, now})).to.be.ok()
|
|
||||||
after.fns.cron {now}
|
|
||||||
before.stats.mp=after.stats.mp #FIXME
|
|
||||||
switch options.expect
|
|
||||||
when 'losePoints' then expectLostPoints(before,after,'daily')
|
|
||||||
when 'noChange' then expectNoChange(before,after)
|
|
||||||
when 'noDamage' then expectDayResetNoDamage(before,after)
|
|
||||||
{before,after}
|
|
||||||
|
|
||||||
# These test cases were written assuming that lastCron was run after dayStart
|
|
||||||
# even if currentHour < dayStart and lastCron = yesterday at currentHour.
|
|
||||||
# cronAfterStart makes sure that lastCron is moved to be after dayStart.
|
|
||||||
cronMatrix =
|
|
||||||
steps:
|
|
||||||
|
|
||||||
'due yesterday':
|
|
||||||
defaults: {daysAgo:1, cronAfterStart:true, limitOne: 'daily'}
|
|
||||||
steps:
|
|
||||||
|
|
||||||
'(simple)': {expect:'losePoints'}
|
|
||||||
|
|
||||||
'due today':
|
|
||||||
# NOTE: a strange thing here, moment().startOf('week') is Sunday, but moment.zone(myTimeZone).startOf('week') is Monday.
|
|
||||||
defaults: {repeat:{su:true,m:true,t:true,w:true,th:true,f:true,s:true}}
|
|
||||||
steps:
|
|
||||||
'pre-dayStart':
|
|
||||||
defaults: {currentHour:3, dayStart:4, shouldDo:true}
|
|
||||||
steps:
|
|
||||||
'checked': {checked: true, expect:'noChange'}
|
|
||||||
'un-checked': {checked: false, expect:'noChange'}
|
|
||||||
'post-dayStart':
|
|
||||||
defaults: {currentHour:5, dayStart:4, shouldDo:true}
|
|
||||||
steps:
|
|
||||||
'checked': {checked:true, expect:'noDamage'}
|
|
||||||
'unchecked': {checked:false, expect: 'losePoints'}
|
|
||||||
|
|
||||||
'NOT due today':
|
|
||||||
defaults: {repeat:{su:true,m:false,t:true,w:true,th:true,f:true,s:true}}
|
|
||||||
steps:
|
|
||||||
'pre-dayStart':
|
|
||||||
defaults: {currentHour:3, dayStart:4, shouldDo:true}
|
|
||||||
steps:
|
|
||||||
'checked': {checked: true, expect:'noChange'}
|
|
||||||
'un-checked': {checked: false, expect:'noChange'}
|
|
||||||
'post-dayStart':
|
|
||||||
defaults: {currentHour:5, dayStart:4, shouldDo:false}
|
|
||||||
steps:
|
|
||||||
'checked': {checked:true, expect:'noDamage'}
|
|
||||||
'unchecked': {checked:false, expect: 'losePoints'}
|
|
||||||
|
|
||||||
'not due yesterday':
|
|
||||||
defaults: repeatWithoutLastWeekday()
|
|
||||||
steps:
|
|
||||||
'(simple)': {expect:'noDamage'}
|
|
||||||
'post-dayStart': {currentHour:5,dayStart:4, expect:'noDamage'}
|
|
||||||
'pre-dayStart': {currentHour:3, dayStart:4, expect:'noChange'}
|
|
||||||
|
|
||||||
recurseCronMatrix = (obj, options={}) ->
|
|
||||||
if obj.steps
|
|
||||||
_.each obj.steps, (step, text) ->
|
|
||||||
o = _.cloneDeep options
|
|
||||||
o.text ?= ''; o.text += " #{text} "
|
|
||||||
recurseCronMatrix step, _.defaults(o,obj.defaults)
|
|
||||||
else
|
|
||||||
it "#{options.text}", -> runCron(_.defaults(obj,options))
|
|
||||||
recurseCronMatrix(cronMatrix)
|
|
||||||
|
|
||||||
describe 'Helper', ->
|
|
||||||
|
|
||||||
it 'calculates gold coins', ->
|
|
||||||
expect(shared.gold(10)).to.eql 10
|
|
||||||
expect(shared.gold(1.957)).to.eql 1
|
|
||||||
expect(shared.gold()).to.eql 0
|
|
||||||
|
|
||||||
it 'calculates silver coins', ->
|
|
||||||
expect(shared.silver(10)).to.eql 0
|
|
||||||
expect(shared.silver(1.957)).to.eql 95
|
|
||||||
expect(shared.silver(0.01)).to.eql "01"
|
|
||||||
expect(shared.silver()).to.eql "00"
|
|
||||||
|
|
||||||
it 'calculates experience to next level', ->
|
|
||||||
expect(shared.tnl 1).to.eql 150
|
|
||||||
expect(shared.tnl 2).to.eql 160
|
|
||||||
expect(shared.tnl 10).to.eql 260
|
|
||||||
expect(shared.tnl 99).to.eql 3580
|
|
||||||
|
|
||||||
it 'calculates the start of the day', ->
|
|
||||||
fstr = 'YYYY-MM-DD HH:mm:ss'
|
|
||||||
today = '2013-01-01 00:00:00'
|
|
||||||
# get the timezone for the day, so the test case doesn't fail
|
|
||||||
# if you run it during daylight savings time because by default
|
|
||||||
# it uses moment().zone() which is the current minute offset
|
|
||||||
zone = moment(today).zone()
|
|
||||||
expect(shared.startOfDay({now: new Date(2013, 0, 1, 0)}, timezoneOffset:zone).format(fstr)).to.eql today
|
|
||||||
expect(shared.startOfDay({now: new Date(2013, 0, 1, 5)}, timezoneOffset:zone).format(fstr)).to.eql today
|
|
||||||
expect(shared.startOfDay({now: new Date(2013, 0, 1, 23, 59, 59), timezoneOffset:zone}).format(fstr)).to.eql today
|
|
||||||
1507
test/common/algos.mocha.js
Normal file
1507
test/common/algos.mocha.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,418 +0,0 @@
|
|||||||
_ = require 'lodash'
|
|
||||||
expect = require 'expect.js'
|
|
||||||
sinon = require 'sinon'
|
|
||||||
moment = require 'moment'
|
|
||||||
shared = require '../../common/script/index.js'
|
|
||||||
shared.i18n.translations = require('../../website/src/libs/i18n.js').translations
|
|
||||||
|
|
||||||
repeatWithoutLastWeekday = ()->
|
|
||||||
repeat = {su:true,m:true,t:true,w:true,th:true,f:true,s:true}
|
|
||||||
if shared.startOfWeek(moment().zone(0)).isoWeekday() == 1 # Monday
|
|
||||||
repeat.su = false
|
|
||||||
else
|
|
||||||
repeat.s = false
|
|
||||||
{repeat: repeat}
|
|
||||||
|
|
||||||
### Helper Functions ####
|
|
||||||
# @TODO: Refactor into helper file
|
|
||||||
newUser = (addTasks=true)->
|
|
||||||
buffs = {per:0, int:0, con:0, str:0, stealth: 0, streaks: false}
|
|
||||||
user =
|
|
||||||
auth:
|
|
||||||
timestamps: {}
|
|
||||||
stats: {str:1, con:1, per:1, int:1, mp: 32, class: 'warrior', buffs: buffs}
|
|
||||||
items:
|
|
||||||
lastDrop:
|
|
||||||
count: 0
|
|
||||||
hatchingPotions: {}
|
|
||||||
eggs: {}
|
|
||||||
food: {}
|
|
||||||
gear:
|
|
||||||
equipped: {}
|
|
||||||
costume: {}
|
|
||||||
party:
|
|
||||||
quest:
|
|
||||||
progress:
|
|
||||||
down: 0
|
|
||||||
preferences: {}
|
|
||||||
dailys: []
|
|
||||||
todos: []
|
|
||||||
rewards: []
|
|
||||||
flags: {}
|
|
||||||
achievements: {}
|
|
||||||
contributor:
|
|
||||||
level: 2
|
|
||||||
shared.wrap(user)
|
|
||||||
user.ops.reset(null, ->)
|
|
||||||
if addTasks
|
|
||||||
_.each ['habit', 'todo', 'daily'], (task)->
|
|
||||||
user.ops.addTask {body: {type: task, id: shared.uuid()}}
|
|
||||||
user
|
|
||||||
|
|
||||||
cron = (usr, missedDays=1) ->
|
|
||||||
usr.lastCron = moment().subtract(missedDays,'days')
|
|
||||||
usr.fns.cron()
|
|
||||||
|
|
||||||
describe 'daily/weekly that repeats everyday (default)', ->
|
|
||||||
user = null
|
|
||||||
daily = null
|
|
||||||
weekly = null
|
|
||||||
|
|
||||||
describe 'when startDate is in the future', ->
|
|
||||||
beforeEach ->
|
|
||||||
user = newUser()
|
|
||||||
user.dailys = [
|
|
||||||
shared.taskDefaults({type:'daily', startDate: moment().add(7, 'days'), frequency: 'daily'})
|
|
||||||
shared.taskDefaults({type:'daily', startDate: moment().add(7, 'days'), frequency: 'weekly', repeat: {su:true,m:true,t:true,w:true,th:true,f:true,s:true}})
|
|
||||||
]
|
|
||||||
daily = user.dailys[0]
|
|
||||||
weekly = user.dailys[1]
|
|
||||||
|
|
||||||
it 'does not damage user for not completing it', ->
|
|
||||||
cron(user)
|
|
||||||
expect(user.stats.hp).to.be 50
|
|
||||||
|
|
||||||
it 'does not change value on cron if daily is incomplete', ->
|
|
||||||
cron(user)
|
|
||||||
expect(daily.value).to.be 0
|
|
||||||
expect(weekly.value).to.be 0
|
|
||||||
|
|
||||||
it 'does not reset checklists if daily is not marked as complete', ->
|
|
||||||
checklist = [
|
|
||||||
{
|
|
||||||
'text' : '1',
|
|
||||||
'id' : 'checklist-one',
|
|
||||||
'completed' : true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'text' : '2',
|
|
||||||
'id' : 'checklist-two',
|
|
||||||
'completed' : true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'text' : '3',
|
|
||||||
'id' : 'checklist-three',
|
|
||||||
'completed' : false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
daily.checklist = checklist
|
|
||||||
weekly.checklist = checklist
|
|
||||||
cron(user)
|
|
||||||
|
|
||||||
expect(daily.checklist[0].completed).to.be true
|
|
||||||
expect(daily.checklist[1].completed).to.be true
|
|
||||||
expect(daily.checklist[2].completed).to.be false
|
|
||||||
|
|
||||||
expect(weekly.checklist[0].completed).to.be true
|
|
||||||
expect(weekly.checklist[1].completed).to.be true
|
|
||||||
expect(weekly.checklist[2].completed).to.be false
|
|
||||||
|
|
||||||
it 'resets checklists if daily is marked as complete', ->
|
|
||||||
checklist = [
|
|
||||||
{
|
|
||||||
'text' : '1',
|
|
||||||
'id' : 'checklist-one',
|
|
||||||
'completed' : true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'text' : '2',
|
|
||||||
'id' : 'checklist-two',
|
|
||||||
'completed' : true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'text' : '3',
|
|
||||||
'id' : 'checklist-three',
|
|
||||||
'completed' : false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
daily.checklist = checklist
|
|
||||||
weekly.checklist = checklist
|
|
||||||
daily.completed = true
|
|
||||||
weekly.completed = true
|
|
||||||
cron(user)
|
|
||||||
|
|
||||||
_.each daily.checklist, (box)->
|
|
||||||
expect(box.completed).to.be false
|
|
||||||
|
|
||||||
_.each weekly.checklist, (box)->
|
|
||||||
expect(box.completed).to.be false
|
|
||||||
|
|
||||||
it 'is due on startDate', ->
|
|
||||||
daily_due_today = shared.shouldDo moment(), daily
|
|
||||||
daily_due_on_start_date = shared.shouldDo moment().add(7, 'days'), daily
|
|
||||||
|
|
||||||
expect(daily_due_today).to.be false
|
|
||||||
expect(daily_due_on_start_date).to.be true
|
|
||||||
|
|
||||||
weekly_due_today = shared.shouldDo moment(), weekly
|
|
||||||
weekly_due_on_start_date = shared.shouldDo moment().add(7, 'days'), weekly
|
|
||||||
|
|
||||||
expect(weekly_due_today).to.be false
|
|
||||||
expect(weekly_due_on_start_date).to.be true
|
|
||||||
|
|
||||||
describe 'when startDate is in the past', ->
|
|
||||||
beforeEach ->
|
|
||||||
user = newUser()
|
|
||||||
user.dailys = [
|
|
||||||
shared.taskDefaults({type:'daily', startDate: moment().subtract(7, 'days'), frequency: 'daily'})
|
|
||||||
shared.taskDefaults({type:'daily', startDate: moment().subtract(7, 'days'), frequency: 'weekly'})
|
|
||||||
]
|
|
||||||
daily = user.dailys[0]
|
|
||||||
weekly = user.dailys[1]
|
|
||||||
|
|
||||||
it 'does damage user for not completing it', ->
|
|
||||||
cron(user)
|
|
||||||
expect(user.stats.hp).to.be.lessThan 50
|
|
||||||
|
|
||||||
it 'decreases value on cron if daily is incomplete', ->
|
|
||||||
cron(user, 1)
|
|
||||||
expect(daily.value).to.be -1
|
|
||||||
expect(weekly.value).to.be -1
|
|
||||||
|
|
||||||
it 'decreases value on cron once only if daily is incomplete and multiple days are missed', ->
|
|
||||||
cron(user, 7)
|
|
||||||
expect(daily.value).to.be -1
|
|
||||||
expect(weekly.value).to.be -1
|
|
||||||
|
|
||||||
it 'resets checklists if daily is not marked as complete', ->
|
|
||||||
checklist = [
|
|
||||||
{
|
|
||||||
'text' : '1',
|
|
||||||
'id' : 'checklist-one',
|
|
||||||
'completed' : true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'text' : '2',
|
|
||||||
'id' : 'checklist-two',
|
|
||||||
'completed' : true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'text' : '3',
|
|
||||||
'id' : 'checklist-three',
|
|
||||||
'completed' : false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
daily.checklist = checklist
|
|
||||||
weekly.checklist = checklist
|
|
||||||
cron(user)
|
|
||||||
|
|
||||||
_.each daily.checklist, (box)->
|
|
||||||
expect(box.completed).to.be false
|
|
||||||
|
|
||||||
_.each weekly.checklist, (box)->
|
|
||||||
expect(box.completed).to.be false
|
|
||||||
|
|
||||||
it 'resets checklists if daily is marked as complete', ->
|
|
||||||
checklist = [
|
|
||||||
{
|
|
||||||
'text' : '1',
|
|
||||||
'id' : 'checklist-one',
|
|
||||||
'completed' : true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'text' : '2',
|
|
||||||
'id' : 'checklist-two',
|
|
||||||
'completed' : true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'text' : '3',
|
|
||||||
'id' : 'checklist-three',
|
|
||||||
'completed' : false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
daily.checklist = checklist
|
|
||||||
daily.completed = true
|
|
||||||
weekly.checklist = checklist
|
|
||||||
weekly.completed = true
|
|
||||||
cron(user)
|
|
||||||
|
|
||||||
_.each daily.checklist, (box)->
|
|
||||||
expect(box.completed).to.be false
|
|
||||||
|
|
||||||
_.each weekly.checklist, (box)->
|
|
||||||
expect(box.completed).to.be false
|
|
||||||
|
|
||||||
describe 'when startDate is today', ->
|
|
||||||
beforeEach ->
|
|
||||||
user = newUser()
|
|
||||||
user.dailys = [
|
|
||||||
# Must set start date to yesterday, because cron mock sets last cron to yesterday
|
|
||||||
shared.taskDefaults({type:'daily', startDate: moment().subtract(1, 'days'), frequency: 'daily'})
|
|
||||||
shared.taskDefaults({type:'daily', startDate: moment().subtract(1, 'days'), frequency: 'weekly'})
|
|
||||||
]
|
|
||||||
daily = user.dailys[0]
|
|
||||||
weekly = user.dailys[1]
|
|
||||||
|
|
||||||
it 'does damage user for not completing it', ->
|
|
||||||
cron(user)
|
|
||||||
expect(user.stats.hp).to.be.lessThan 50
|
|
||||||
|
|
||||||
it 'decreases value on cron if daily is incomplete', ->
|
|
||||||
cron(user)
|
|
||||||
expect(daily.value).to.be.lessThan 0
|
|
||||||
expect(weekly.value).to.be.lessThan 0
|
|
||||||
|
|
||||||
it 'resets checklists if daily is not marked as complete', ->
|
|
||||||
checklist = [
|
|
||||||
{
|
|
||||||
'text' : '1',
|
|
||||||
'id' : 'checklist-one',
|
|
||||||
'completed' : true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'text' : '2',
|
|
||||||
'id' : 'checklist-two',
|
|
||||||
'completed' : true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'text' : '3',
|
|
||||||
'id' : 'checklist-three',
|
|
||||||
'completed' : false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
daily.checklist = checklist
|
|
||||||
weekly.checklist = checklist
|
|
||||||
cron(user)
|
|
||||||
|
|
||||||
_.each daily.checklist, (box)->
|
|
||||||
expect(box.completed).to.be false
|
|
||||||
|
|
||||||
_.each weekly.checklist, (box)->
|
|
||||||
expect(box.completed).to.be false
|
|
||||||
|
|
||||||
it 'resets checklists if daily is marked as complete', ->
|
|
||||||
checklist = [
|
|
||||||
{
|
|
||||||
'text' : '1',
|
|
||||||
'id' : 'checklist-one',
|
|
||||||
'completed' : true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'text' : '2',
|
|
||||||
'id' : 'checklist-two',
|
|
||||||
'completed' : true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'text' : '3',
|
|
||||||
'id' : 'checklist-three',
|
|
||||||
'completed' : false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
daily.checklist = checklist
|
|
||||||
daily.completed = true
|
|
||||||
weekly.checklist = checklist
|
|
||||||
weekly.completed = true
|
|
||||||
cron(user)
|
|
||||||
|
|
||||||
_.each daily.checklist, (box)->
|
|
||||||
expect(box.completed).to.be false
|
|
||||||
|
|
||||||
_.each weekly.checklist, (box)->
|
|
||||||
expect(box.completed).to.be false
|
|
||||||
|
|
||||||
describe 'daily that repeats every x days', ->
|
|
||||||
user = null
|
|
||||||
daily = null
|
|
||||||
|
|
||||||
beforeEach ->
|
|
||||||
user = newUser()
|
|
||||||
user.dailys = [ shared.taskDefaults({type:'daily', startDate: moment(), frequency: 'daily'}) ]
|
|
||||||
daily = user.dailys[0]
|
|
||||||
|
|
||||||
_.times 11, (due) ->
|
|
||||||
|
|
||||||
it 'where x equals ' + due, ->
|
|
||||||
daily.everyX = due
|
|
||||||
|
|
||||||
_.times 30, (day) ->
|
|
||||||
isDue = shared.shouldDo moment().add(day, 'days'), daily
|
|
||||||
expect(isDue).to.be true if day % due == 0
|
|
||||||
expect(isDue).to.be false if day % due != 0
|
|
||||||
|
|
||||||
describe 'daily that repeats every X days when multiple days are missed', ->
|
|
||||||
everyX = 3
|
|
||||||
startDateDaysAgo = everyX * 3
|
|
||||||
user = null
|
|
||||||
daily = null
|
|
||||||
|
|
||||||
describe 'including missing a due date', ->
|
|
||||||
missedDays = everyX * 2 + 1
|
|
||||||
|
|
||||||
beforeEach ->
|
|
||||||
user = newUser()
|
|
||||||
user.dailys = [
|
|
||||||
shared.taskDefaults({type:'daily', startDate: moment().subtract(startDateDaysAgo, 'days'), frequency: 'daily', everyX: everyX})
|
|
||||||
]
|
|
||||||
daily = user.dailys[0]
|
|
||||||
|
|
||||||
it 'decreases value on cron once only if daily is incomplete', ->
|
|
||||||
cron(user, missedDays)
|
|
||||||
expect(daily.value).to.be -1
|
|
||||||
|
|
||||||
it 'resets checklists if daily is incomplete', ->
|
|
||||||
checklist = [
|
|
||||||
{
|
|
||||||
'text' : '1',
|
|
||||||
'id' : 'checklist-one',
|
|
||||||
'completed' : true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
daily.checklist = checklist
|
|
||||||
cron(user, missedDays)
|
|
||||||
_.each daily.checklist, (box)->
|
|
||||||
expect(box.completed).to.be false
|
|
||||||
|
|
||||||
it 'resets checklists if daily is marked as complete', ->
|
|
||||||
checklist = [
|
|
||||||
{
|
|
||||||
'text' : '1',
|
|
||||||
'id' : 'checklist-one',
|
|
||||||
'completed' : true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
daily.checklist = checklist
|
|
||||||
daily.completed = true
|
|
||||||
cron(user, missedDays)
|
|
||||||
_.each daily.checklist, (box)->
|
|
||||||
expect(box.completed).to.be false
|
|
||||||
|
|
||||||
describe 'but not missing a due date', ->
|
|
||||||
missedDays = everyX - 1
|
|
||||||
|
|
||||||
beforeEach ->
|
|
||||||
user = newUser()
|
|
||||||
user.dailys = [
|
|
||||||
shared.taskDefaults({type:'daily', startDate: moment().subtract(startDateDaysAgo, 'days'), frequency: 'daily', everyX: everyX})
|
|
||||||
]
|
|
||||||
daily = user.dailys[0]
|
|
||||||
|
|
||||||
it 'does not decrease value on cron', ->
|
|
||||||
cron(user, missedDays)
|
|
||||||
expect(daily.value).to.be 0
|
|
||||||
|
|
||||||
it 'does not reset checklists if daily is incomplete', ->
|
|
||||||
checklist = [
|
|
||||||
{
|
|
||||||
'text' : '1',
|
|
||||||
'id' : 'checklist-one',
|
|
||||||
'completed' : true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
daily.checklist = checklist
|
|
||||||
cron(user, missedDays)
|
|
||||||
_.each daily.checklist, (box)->
|
|
||||||
expect(box.completed).to.be true
|
|
||||||
|
|
||||||
it 'resets checklists if daily is marked as complete', ->
|
|
||||||
checklist = [
|
|
||||||
{
|
|
||||||
'text' : '1',
|
|
||||||
'id' : 'checklist-one',
|
|
||||||
'completed' : true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
daily.checklist = checklist
|
|
||||||
daily.completed = true
|
|
||||||
cron(user, missedDays)
|
|
||||||
_.each daily.checklist, (box)->
|
|
||||||
expect(box.completed).to.be false
|
|
||||||
541
test/common/dailies.js
Normal file
541
test/common/dailies.js
Normal file
@@ -0,0 +1,541 @@
|
|||||||
|
(function() {
|
||||||
|
var _, cron, expect, moment, newUser, repeatWithoutLastWeekday, shared, sinon;
|
||||||
|
|
||||||
|
_ = require('lodash');
|
||||||
|
|
||||||
|
expect = require('expect.js');
|
||||||
|
|
||||||
|
sinon = require('sinon');
|
||||||
|
|
||||||
|
moment = require('moment');
|
||||||
|
|
||||||
|
shared = require('../../common/script/index.js');
|
||||||
|
|
||||||
|
shared.i18n.translations = require('../../website/src/libs/i18n.js').translations;
|
||||||
|
|
||||||
|
repeatWithoutLastWeekday = function() {
|
||||||
|
var repeat;
|
||||||
|
repeat = {
|
||||||
|
su: true,
|
||||||
|
m: true,
|
||||||
|
t: true,
|
||||||
|
w: true,
|
||||||
|
th: true,
|
||||||
|
f: true,
|
||||||
|
s: true
|
||||||
|
};
|
||||||
|
if (shared.startOfWeek(moment().zone(0)).isoWeekday() === 1) {
|
||||||
|
repeat.su = false;
|
||||||
|
} else {
|
||||||
|
repeat.s = false;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
repeat: repeat
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Helper Functions */
|
||||||
|
|
||||||
|
newUser = function(addTasks) {
|
||||||
|
var buffs, user;
|
||||||
|
if (addTasks == null) {
|
||||||
|
addTasks = true;
|
||||||
|
}
|
||||||
|
buffs = {
|
||||||
|
per: 0,
|
||||||
|
int: 0,
|
||||||
|
con: 0,
|
||||||
|
str: 0,
|
||||||
|
stealth: 0,
|
||||||
|
streaks: false
|
||||||
|
};
|
||||||
|
user = {
|
||||||
|
auth: {
|
||||||
|
timestamps: {}
|
||||||
|
},
|
||||||
|
stats: {
|
||||||
|
str: 1,
|
||||||
|
con: 1,
|
||||||
|
per: 1,
|
||||||
|
int: 1,
|
||||||
|
mp: 32,
|
||||||
|
"class": 'warrior',
|
||||||
|
buffs: buffs
|
||||||
|
},
|
||||||
|
items: {
|
||||||
|
lastDrop: {
|
||||||
|
count: 0
|
||||||
|
},
|
||||||
|
hatchingPotions: {},
|
||||||
|
eggs: {},
|
||||||
|
food: {},
|
||||||
|
gear: {
|
||||||
|
equipped: {},
|
||||||
|
costume: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
party: {
|
||||||
|
quest: {
|
||||||
|
progress: {
|
||||||
|
down: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
preferences: {},
|
||||||
|
dailys: [],
|
||||||
|
todos: [],
|
||||||
|
rewards: [],
|
||||||
|
flags: {},
|
||||||
|
achievements: {},
|
||||||
|
contributor: {
|
||||||
|
level: 2
|
||||||
|
}
|
||||||
|
};
|
||||||
|
shared.wrap(user);
|
||||||
|
user.ops.reset(null, function() {});
|
||||||
|
if (addTasks) {
|
||||||
|
_.each(['habit', 'todo', 'daily'], function(task) {
|
||||||
|
return user.ops.addTask({
|
||||||
|
body: {
|
||||||
|
type: task,
|
||||||
|
id: shared.uuid()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return user;
|
||||||
|
};
|
||||||
|
|
||||||
|
cron = function(usr, missedDays) {
|
||||||
|
if (missedDays == null) {
|
||||||
|
missedDays = 1;
|
||||||
|
}
|
||||||
|
usr.lastCron = moment().subtract(missedDays, 'days');
|
||||||
|
return usr.fns.cron();
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('daily/weekly that repeats everyday (default)', function() {
|
||||||
|
var daily, user, weekly;
|
||||||
|
user = null;
|
||||||
|
daily = null;
|
||||||
|
weekly = null;
|
||||||
|
describe('when startDate is in the future', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
user = newUser();
|
||||||
|
user.dailys = [
|
||||||
|
shared.taskDefaults({
|
||||||
|
type: 'daily',
|
||||||
|
startDate: moment().add(7, 'days'),
|
||||||
|
frequency: 'daily'
|
||||||
|
}), shared.taskDefaults({
|
||||||
|
type: 'daily',
|
||||||
|
startDate: moment().add(7, 'days'),
|
||||||
|
frequency: 'weekly',
|
||||||
|
repeat: {
|
||||||
|
su: true,
|
||||||
|
m: true,
|
||||||
|
t: true,
|
||||||
|
w: true,
|
||||||
|
th: true,
|
||||||
|
f: true,
|
||||||
|
s: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
];
|
||||||
|
daily = user.dailys[0];
|
||||||
|
return weekly = user.dailys[1];
|
||||||
|
});
|
||||||
|
it('does not damage user for not completing it', function() {
|
||||||
|
cron(user);
|
||||||
|
return expect(user.stats.hp).to.be(50);
|
||||||
|
});
|
||||||
|
it('does not change value on cron if daily is incomplete', function() {
|
||||||
|
cron(user);
|
||||||
|
expect(daily.value).to.be(0);
|
||||||
|
return expect(weekly.value).to.be(0);
|
||||||
|
});
|
||||||
|
it('does not reset checklists if daily is not marked as complete', function() {
|
||||||
|
var checklist;
|
||||||
|
checklist = [
|
||||||
|
{
|
||||||
|
'text': '1',
|
||||||
|
'id': 'checklist-one',
|
||||||
|
'completed': true
|
||||||
|
}, {
|
||||||
|
'text': '2',
|
||||||
|
'id': 'checklist-two',
|
||||||
|
'completed': true
|
||||||
|
}, {
|
||||||
|
'text': '3',
|
||||||
|
'id': 'checklist-three',
|
||||||
|
'completed': false
|
||||||
|
}
|
||||||
|
];
|
||||||
|
daily.checklist = checklist;
|
||||||
|
weekly.checklist = checklist;
|
||||||
|
cron(user);
|
||||||
|
expect(daily.checklist[0].completed).to.be(true);
|
||||||
|
expect(daily.checklist[1].completed).to.be(true);
|
||||||
|
expect(daily.checklist[2].completed).to.be(false);
|
||||||
|
expect(weekly.checklist[0].completed).to.be(true);
|
||||||
|
expect(weekly.checklist[1].completed).to.be(true);
|
||||||
|
return expect(weekly.checklist[2].completed).to.be(false);
|
||||||
|
});
|
||||||
|
it('resets checklists if daily is marked as complete', function() {
|
||||||
|
var checklist;
|
||||||
|
checklist = [
|
||||||
|
{
|
||||||
|
'text': '1',
|
||||||
|
'id': 'checklist-one',
|
||||||
|
'completed': true
|
||||||
|
}, {
|
||||||
|
'text': '2',
|
||||||
|
'id': 'checklist-two',
|
||||||
|
'completed': true
|
||||||
|
}, {
|
||||||
|
'text': '3',
|
||||||
|
'id': 'checklist-three',
|
||||||
|
'completed': false
|
||||||
|
}
|
||||||
|
];
|
||||||
|
daily.checklist = checklist;
|
||||||
|
weekly.checklist = checklist;
|
||||||
|
daily.completed = true;
|
||||||
|
weekly.completed = true;
|
||||||
|
cron(user);
|
||||||
|
_.each(daily.checklist, function(box) {
|
||||||
|
return expect(box.completed).to.be(false);
|
||||||
|
});
|
||||||
|
return _.each(weekly.checklist, function(box) {
|
||||||
|
return expect(box.completed).to.be(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return it('is due on startDate', function() {
|
||||||
|
var daily_due_on_start_date, daily_due_today, weekly_due_on_start_date, weekly_due_today;
|
||||||
|
daily_due_today = shared.shouldDo(moment(), daily);
|
||||||
|
daily_due_on_start_date = shared.shouldDo(moment().add(7, 'days'), daily);
|
||||||
|
expect(daily_due_today).to.be(false);
|
||||||
|
expect(daily_due_on_start_date).to.be(true);
|
||||||
|
weekly_due_today = shared.shouldDo(moment(), weekly);
|
||||||
|
weekly_due_on_start_date = shared.shouldDo(moment().add(7, 'days'), weekly);
|
||||||
|
expect(weekly_due_today).to.be(false);
|
||||||
|
return expect(weekly_due_on_start_date).to.be(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('when startDate is in the past', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
user = newUser();
|
||||||
|
user.dailys = [
|
||||||
|
shared.taskDefaults({
|
||||||
|
type: 'daily',
|
||||||
|
startDate: moment().subtract(7, 'days'),
|
||||||
|
frequency: 'daily'
|
||||||
|
}), shared.taskDefaults({
|
||||||
|
type: 'daily',
|
||||||
|
startDate: moment().subtract(7, 'days'),
|
||||||
|
frequency: 'weekly'
|
||||||
|
})
|
||||||
|
];
|
||||||
|
daily = user.dailys[0];
|
||||||
|
return weekly = user.dailys[1];
|
||||||
|
});
|
||||||
|
it('does damage user for not completing it', function() {
|
||||||
|
cron(user);
|
||||||
|
return expect(user.stats.hp).to.be.lessThan(50);
|
||||||
|
});
|
||||||
|
it('decreases value on cron if daily is incomplete', function() {
|
||||||
|
cron(user, 1);
|
||||||
|
expect(daily.value).to.be(-1);
|
||||||
|
return expect(weekly.value).to.be(-1);
|
||||||
|
});
|
||||||
|
it('decreases value on cron once only if daily is incomplete and multiple days are missed', function() {
|
||||||
|
cron(user, 7);
|
||||||
|
expect(daily.value).to.be(-1);
|
||||||
|
return expect(weekly.value).to.be(-1);
|
||||||
|
});
|
||||||
|
it('resets checklists if daily is not marked as complete', function() {
|
||||||
|
var checklist;
|
||||||
|
checklist = [
|
||||||
|
{
|
||||||
|
'text': '1',
|
||||||
|
'id': 'checklist-one',
|
||||||
|
'completed': true
|
||||||
|
}, {
|
||||||
|
'text': '2',
|
||||||
|
'id': 'checklist-two',
|
||||||
|
'completed': true
|
||||||
|
}, {
|
||||||
|
'text': '3',
|
||||||
|
'id': 'checklist-three',
|
||||||
|
'completed': false
|
||||||
|
}
|
||||||
|
];
|
||||||
|
daily.checklist = checklist;
|
||||||
|
weekly.checklist = checklist;
|
||||||
|
cron(user);
|
||||||
|
_.each(daily.checklist, function(box) {
|
||||||
|
return expect(box.completed).to.be(false);
|
||||||
|
});
|
||||||
|
return _.each(weekly.checklist, function(box) {
|
||||||
|
return expect(box.completed).to.be(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return it('resets checklists if daily is marked as complete', function() {
|
||||||
|
var checklist;
|
||||||
|
checklist = [
|
||||||
|
{
|
||||||
|
'text': '1',
|
||||||
|
'id': 'checklist-one',
|
||||||
|
'completed': true
|
||||||
|
}, {
|
||||||
|
'text': '2',
|
||||||
|
'id': 'checklist-two',
|
||||||
|
'completed': true
|
||||||
|
}, {
|
||||||
|
'text': '3',
|
||||||
|
'id': 'checklist-three',
|
||||||
|
'completed': false
|
||||||
|
}
|
||||||
|
];
|
||||||
|
daily.checklist = checklist;
|
||||||
|
daily.completed = true;
|
||||||
|
weekly.checklist = checklist;
|
||||||
|
weekly.completed = true;
|
||||||
|
cron(user);
|
||||||
|
_.each(daily.checklist, function(box) {
|
||||||
|
return expect(box.completed).to.be(false);
|
||||||
|
});
|
||||||
|
return _.each(weekly.checklist, function(box) {
|
||||||
|
return expect(box.completed).to.be(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return describe('when startDate is today', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
user = newUser();
|
||||||
|
user.dailys = [
|
||||||
|
shared.taskDefaults({
|
||||||
|
type: 'daily',
|
||||||
|
startDate: moment().subtract(1, 'days'),
|
||||||
|
frequency: 'daily'
|
||||||
|
}), shared.taskDefaults({
|
||||||
|
type: 'daily',
|
||||||
|
startDate: moment().subtract(1, 'days'),
|
||||||
|
frequency: 'weekly'
|
||||||
|
})
|
||||||
|
];
|
||||||
|
daily = user.dailys[0];
|
||||||
|
return weekly = user.dailys[1];
|
||||||
|
});
|
||||||
|
it('does damage user for not completing it', function() {
|
||||||
|
cron(user);
|
||||||
|
return expect(user.stats.hp).to.be.lessThan(50);
|
||||||
|
});
|
||||||
|
it('decreases value on cron if daily is incomplete', function() {
|
||||||
|
cron(user);
|
||||||
|
expect(daily.value).to.be.lessThan(0);
|
||||||
|
return expect(weekly.value).to.be.lessThan(0);
|
||||||
|
});
|
||||||
|
it('resets checklists if daily is not marked as complete', function() {
|
||||||
|
var checklist;
|
||||||
|
checklist = [
|
||||||
|
{
|
||||||
|
'text': '1',
|
||||||
|
'id': 'checklist-one',
|
||||||
|
'completed': true
|
||||||
|
}, {
|
||||||
|
'text': '2',
|
||||||
|
'id': 'checklist-two',
|
||||||
|
'completed': true
|
||||||
|
}, {
|
||||||
|
'text': '3',
|
||||||
|
'id': 'checklist-three',
|
||||||
|
'completed': false
|
||||||
|
}
|
||||||
|
];
|
||||||
|
daily.checklist = checklist;
|
||||||
|
weekly.checklist = checklist;
|
||||||
|
cron(user);
|
||||||
|
_.each(daily.checklist, function(box) {
|
||||||
|
return expect(box.completed).to.be(false);
|
||||||
|
});
|
||||||
|
return _.each(weekly.checklist, function(box) {
|
||||||
|
return expect(box.completed).to.be(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return it('resets checklists if daily is marked as complete', function() {
|
||||||
|
var checklist;
|
||||||
|
checklist = [
|
||||||
|
{
|
||||||
|
'text': '1',
|
||||||
|
'id': 'checklist-one',
|
||||||
|
'completed': true
|
||||||
|
}, {
|
||||||
|
'text': '2',
|
||||||
|
'id': 'checklist-two',
|
||||||
|
'completed': true
|
||||||
|
}, {
|
||||||
|
'text': '3',
|
||||||
|
'id': 'checklist-three',
|
||||||
|
'completed': false
|
||||||
|
}
|
||||||
|
];
|
||||||
|
daily.checklist = checklist;
|
||||||
|
daily.completed = true;
|
||||||
|
weekly.checklist = checklist;
|
||||||
|
weekly.completed = true;
|
||||||
|
cron(user);
|
||||||
|
_.each(daily.checklist, function(box) {
|
||||||
|
return expect(box.completed).to.be(false);
|
||||||
|
});
|
||||||
|
return _.each(weekly.checklist, function(box) {
|
||||||
|
return expect(box.completed).to.be(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('daily that repeats every x days', function() {
|
||||||
|
var daily, user;
|
||||||
|
user = null;
|
||||||
|
daily = null;
|
||||||
|
beforeEach(function() {
|
||||||
|
user = newUser();
|
||||||
|
user.dailys = [
|
||||||
|
shared.taskDefaults({
|
||||||
|
type: 'daily',
|
||||||
|
startDate: moment(),
|
||||||
|
frequency: 'daily'
|
||||||
|
})
|
||||||
|
];
|
||||||
|
return daily = user.dailys[0];
|
||||||
|
});
|
||||||
|
return _.times(11, function(due) {
|
||||||
|
return it('where x equals ' + due, function() {
|
||||||
|
daily.everyX = due;
|
||||||
|
return _.times(30, function(day) {
|
||||||
|
var isDue;
|
||||||
|
isDue = shared.shouldDo(moment().add(day, 'days'), daily);
|
||||||
|
if (day % due === 0) {
|
||||||
|
expect(isDue).to.be(true);
|
||||||
|
}
|
||||||
|
if (day % due !== 0) {
|
||||||
|
return expect(isDue).to.be(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('daily that repeats every X days when multiple days are missed', function() {
|
||||||
|
var daily, everyX, startDateDaysAgo, user;
|
||||||
|
everyX = 3;
|
||||||
|
startDateDaysAgo = everyX * 3;
|
||||||
|
user = null;
|
||||||
|
daily = null;
|
||||||
|
describe('including missing a due date', function() {
|
||||||
|
var missedDays;
|
||||||
|
missedDays = everyX * 2 + 1;
|
||||||
|
beforeEach(function() {
|
||||||
|
user = newUser();
|
||||||
|
user.dailys = [
|
||||||
|
shared.taskDefaults({
|
||||||
|
type: 'daily',
|
||||||
|
startDate: moment().subtract(startDateDaysAgo, 'days'),
|
||||||
|
frequency: 'daily',
|
||||||
|
everyX: everyX
|
||||||
|
})
|
||||||
|
];
|
||||||
|
return daily = user.dailys[0];
|
||||||
|
});
|
||||||
|
it('decreases value on cron once only if daily is incomplete', function() {
|
||||||
|
cron(user, missedDays);
|
||||||
|
return expect(daily.value).to.be(-1);
|
||||||
|
});
|
||||||
|
it('resets checklists if daily is incomplete', function() {
|
||||||
|
var checklist;
|
||||||
|
checklist = [
|
||||||
|
{
|
||||||
|
'text': '1',
|
||||||
|
'id': 'checklist-one',
|
||||||
|
'completed': true
|
||||||
|
}
|
||||||
|
];
|
||||||
|
daily.checklist = checklist;
|
||||||
|
cron(user, missedDays);
|
||||||
|
return _.each(daily.checklist, function(box) {
|
||||||
|
return expect(box.completed).to.be(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return it('resets checklists if daily is marked as complete', function() {
|
||||||
|
var checklist;
|
||||||
|
checklist = [
|
||||||
|
{
|
||||||
|
'text': '1',
|
||||||
|
'id': 'checklist-one',
|
||||||
|
'completed': true
|
||||||
|
}
|
||||||
|
];
|
||||||
|
daily.checklist = checklist;
|
||||||
|
daily.completed = true;
|
||||||
|
cron(user, missedDays);
|
||||||
|
return _.each(daily.checklist, function(box) {
|
||||||
|
return expect(box.completed).to.be(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return describe('but not missing a due date', function() {
|
||||||
|
var missedDays;
|
||||||
|
missedDays = everyX - 1;
|
||||||
|
beforeEach(function() {
|
||||||
|
user = newUser();
|
||||||
|
user.dailys = [
|
||||||
|
shared.taskDefaults({
|
||||||
|
type: 'daily',
|
||||||
|
startDate: moment().subtract(startDateDaysAgo, 'days'),
|
||||||
|
frequency: 'daily',
|
||||||
|
everyX: everyX
|
||||||
|
})
|
||||||
|
];
|
||||||
|
return daily = user.dailys[0];
|
||||||
|
});
|
||||||
|
it('does not decrease value on cron', function() {
|
||||||
|
cron(user, missedDays);
|
||||||
|
return expect(daily.value).to.be(0);
|
||||||
|
});
|
||||||
|
it('does not reset checklists if daily is incomplete', function() {
|
||||||
|
var checklist;
|
||||||
|
checklist = [
|
||||||
|
{
|
||||||
|
'text': '1',
|
||||||
|
'id': 'checklist-one',
|
||||||
|
'completed': true
|
||||||
|
}
|
||||||
|
];
|
||||||
|
daily.checklist = checklist;
|
||||||
|
cron(user, missedDays);
|
||||||
|
return _.each(daily.checklist, function(box) {
|
||||||
|
return expect(box.completed).to.be(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return it('resets checklists if daily is marked as complete', function() {
|
||||||
|
var checklist;
|
||||||
|
checklist = [
|
||||||
|
{
|
||||||
|
'text': '1',
|
||||||
|
'id': 'checklist-one',
|
||||||
|
'completed': true
|
||||||
|
}
|
||||||
|
];
|
||||||
|
daily.checklist = checklist;
|
||||||
|
daily.completed = true;
|
||||||
|
cron(user, missedDays);
|
||||||
|
return _.each(daily.checklist, function(box) {
|
||||||
|
return expect(box.completed).to.be(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
}).call(this);
|
||||||
@@ -5,4 +5,5 @@
|
|||||||
--growl
|
--growl
|
||||||
--debug
|
--debug
|
||||||
--compilers coffee:coffee-script
|
--compilers coffee:coffee-script
|
||||||
|
--compilers js:babel/register
|
||||||
--globals io
|
--globals io
|
||||||
|
|||||||
@@ -1,82 +0,0 @@
|
|||||||
###
|
|
||||||
1) clone the repo
|
|
||||||
2) npm install
|
|
||||||
3) coffee ./tests/math_samples.coffee
|
|
||||||
|
|
||||||
Current results at https://gist.github.com/lefnire/8049676
|
|
||||||
###
|
|
||||||
|
|
||||||
shared = require '../../../common/script/index.js'
|
|
||||||
_ = require 'lodash'
|
|
||||||
$w = (s)->s.split(' ')
|
|
||||||
|
|
||||||
id = shared.uuid()
|
|
||||||
user =
|
|
||||||
stats:
|
|
||||||
class: 'warrior'
|
|
||||||
lvl:1, hp:50, gp:0, exp:10
|
|
||||||
per:0, int:0, con:0, str:0
|
|
||||||
buffs: {per:0, int:0, con:0, str:0}
|
|
||||||
training: {int:0,con:0,per:0,str:0}
|
|
||||||
preferences: automaticAllocation: false
|
|
||||||
party: quest: key:'evilsanta', progress: {up:0,down:0}
|
|
||||||
achievements: {}
|
|
||||||
items:
|
|
||||||
eggs: {}
|
|
||||||
hatchingPotions: {}
|
|
||||||
food: {}
|
|
||||||
gear:
|
|
||||||
equipped:
|
|
||||||
weapon: 'weapon_warrior_4'
|
|
||||||
armor: 'armor_warrior_4'
|
|
||||||
shield: 'shield_warrior_4'
|
|
||||||
head: 'head_warrior_4'
|
|
||||||
habits: [
|
|
||||||
# we're gonna change this habit's attribute to mess with taskbased allo. Add the others to make sure our _.reduce is legit
|
|
||||||
{id:'a',value:1,type:'habit',attribute:'str'}
|
|
||||||
]
|
|
||||||
dailys: [
|
|
||||||
{id:'b',value:1,type:'daily',attribute:'str'}
|
|
||||||
]
|
|
||||||
todos: [
|
|
||||||
{id:'c',value:1,type:'todo',attribute:'con'}
|
|
||||||
{id:'d',value:1,type:'todo',attribute:'per'}
|
|
||||||
{id:'e',value:1,type:'todo',attribute:'int'}
|
|
||||||
]
|
|
||||||
rewards: []
|
|
||||||
|
|
||||||
modes =
|
|
||||||
flat: _.cloneDeep user
|
|
||||||
classbased_warrior: _.cloneDeep user
|
|
||||||
classbased_rogue: _.cloneDeep user
|
|
||||||
classbased_wizard: _.cloneDeep user
|
|
||||||
classbased_healer: _.cloneDeep user
|
|
||||||
taskbased: _.cloneDeep user
|
|
||||||
|
|
||||||
modes.classbased_warrior.stats.class = 'warrior'
|
|
||||||
modes.classbased_rogue.stats.class = 'rogue'
|
|
||||||
modes.classbased_wizard.stats.class = 'wizard'
|
|
||||||
modes.classbased_healer.stats.class = 'healer'
|
|
||||||
|
|
||||||
_.each $w('flat classbased_warrior classbased_rogue classbased_wizard classbased_healer taskbased'), (mode) ->
|
|
||||||
_.merge modes[mode].preferences,
|
|
||||||
automaticAllocation: true
|
|
||||||
allocationMode: if mode.indexOf('classbased') is 0 then 'classbased' else mode
|
|
||||||
shared.wrap(modes[mode])
|
|
||||||
|
|
||||||
console.log "\n\n================================================"
|
|
||||||
console.log "New Simulation"
|
|
||||||
console.log "================================================\n\n"
|
|
||||||
|
|
||||||
|
|
||||||
_.times [20], (lvl) ->
|
|
||||||
console.log ("[lvl #{lvl}]\n--------------\n")
|
|
||||||
_.each $w('flat classbased_warrior classbased_rogue classbased_wizard classbased_healer taskbased'), (mode) ->
|
|
||||||
u = modes[mode] #local var
|
|
||||||
u.stats.exp = shared.tnl(lvl)+1 # level up
|
|
||||||
_.merge u.stats, {per:0,con:0,int:0,str:0} if mode is 'taskbased' # if task-based, clear stat so we can see clearly which stat got +1
|
|
||||||
u.habits[0].attribute = u.fns.randomVal({str:'str',int:'int',per:'per',con:'con'})
|
|
||||||
u.ops.score {params:{id:u.habits[0].id},direction:'up'}
|
|
||||||
u.fns.updateStats(u.stats) # trigger stats update
|
|
||||||
str = mode + (if mode is 'taskbased' then " (#{u.habits[0].attribute})" else "")
|
|
||||||
console.log str, _.pick(u.stats, $w 'per int con str')
|
|
||||||
164
test/common/simulations/autoAllocate.js
Normal file
164
test/common/simulations/autoAllocate.js
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
(function() {
|
||||||
|
var $w, _, id, modes, shared, user;
|
||||||
|
|
||||||
|
shared = require('../../../common/script/index.js');
|
||||||
|
|
||||||
|
_ = require('lodash');
|
||||||
|
|
||||||
|
$w = function(s) {
|
||||||
|
return s.split(' ');
|
||||||
|
};
|
||||||
|
|
||||||
|
id = shared.uuid();
|
||||||
|
|
||||||
|
user = {
|
||||||
|
stats: {
|
||||||
|
"class": 'warrior',
|
||||||
|
lvl: 1,
|
||||||
|
hp: 50,
|
||||||
|
gp: 0,
|
||||||
|
exp: 10,
|
||||||
|
per: 0,
|
||||||
|
int: 0,
|
||||||
|
con: 0,
|
||||||
|
str: 0,
|
||||||
|
buffs: {
|
||||||
|
per: 0,
|
||||||
|
int: 0,
|
||||||
|
con: 0,
|
||||||
|
str: 0
|
||||||
|
},
|
||||||
|
training: {
|
||||||
|
int: 0,
|
||||||
|
con: 0,
|
||||||
|
per: 0,
|
||||||
|
str: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
preferences: {
|
||||||
|
automaticAllocation: false
|
||||||
|
},
|
||||||
|
party: {
|
||||||
|
quest: {
|
||||||
|
key: 'evilsanta',
|
||||||
|
progress: {
|
||||||
|
up: 0,
|
||||||
|
down: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
achievements: {},
|
||||||
|
items: {
|
||||||
|
eggs: {},
|
||||||
|
hatchingPotions: {},
|
||||||
|
food: {},
|
||||||
|
gear: {
|
||||||
|
equipped: {
|
||||||
|
weapon: 'weapon_warrior_4',
|
||||||
|
armor: 'armor_warrior_4',
|
||||||
|
shield: 'shield_warrior_4',
|
||||||
|
head: 'head_warrior_4'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
habits: [
|
||||||
|
{
|
||||||
|
id: 'a',
|
||||||
|
value: 1,
|
||||||
|
type: 'habit',
|
||||||
|
attribute: 'str'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
dailys: [
|
||||||
|
{
|
||||||
|
id: 'b',
|
||||||
|
value: 1,
|
||||||
|
type: 'daily',
|
||||||
|
attribute: 'str'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
todos: [
|
||||||
|
{
|
||||||
|
id: 'c',
|
||||||
|
value: 1,
|
||||||
|
type: 'todo',
|
||||||
|
attribute: 'con'
|
||||||
|
}, {
|
||||||
|
id: 'd',
|
||||||
|
value: 1,
|
||||||
|
type: 'todo',
|
||||||
|
attribute: 'per'
|
||||||
|
}, {
|
||||||
|
id: 'e',
|
||||||
|
value: 1,
|
||||||
|
type: 'todo',
|
||||||
|
attribute: 'int'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
rewards: []
|
||||||
|
};
|
||||||
|
|
||||||
|
modes = {
|
||||||
|
flat: _.cloneDeep(user),
|
||||||
|
classbased_warrior: _.cloneDeep(user),
|
||||||
|
classbased_rogue: _.cloneDeep(user),
|
||||||
|
classbased_wizard: _.cloneDeep(user),
|
||||||
|
classbased_healer: _.cloneDeep(user),
|
||||||
|
taskbased: _.cloneDeep(user)
|
||||||
|
};
|
||||||
|
|
||||||
|
modes.classbased_warrior.stats["class"] = 'warrior';
|
||||||
|
|
||||||
|
modes.classbased_rogue.stats["class"] = 'rogue';
|
||||||
|
|
||||||
|
modes.classbased_wizard.stats["class"] = 'wizard';
|
||||||
|
|
||||||
|
modes.classbased_healer.stats["class"] = 'healer';
|
||||||
|
|
||||||
|
_.each($w('flat classbased_warrior classbased_rogue classbased_wizard classbased_healer taskbased'), function(mode) {
|
||||||
|
_.merge(modes[mode].preferences, {
|
||||||
|
automaticAllocation: true,
|
||||||
|
allocationMode: mode.indexOf('classbased') === 0 ? 'classbased' : mode
|
||||||
|
});
|
||||||
|
return shared.wrap(modes[mode]);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("\n\n================================================");
|
||||||
|
|
||||||
|
console.log("New Simulation");
|
||||||
|
|
||||||
|
console.log("================================================\n\n");
|
||||||
|
|
||||||
|
_.times([20], function(lvl) {
|
||||||
|
console.log("[lvl " + lvl + "]\n--------------\n");
|
||||||
|
return _.each($w('flat classbased_warrior classbased_rogue classbased_wizard classbased_healer taskbased'), function(mode) {
|
||||||
|
var str, u;
|
||||||
|
u = modes[mode];
|
||||||
|
u.stats.exp = shared.tnl(lvl) + 1;
|
||||||
|
if (mode === 'taskbased') {
|
||||||
|
_.merge(u.stats, {
|
||||||
|
per: 0,
|
||||||
|
con: 0,
|
||||||
|
int: 0,
|
||||||
|
str: 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
u.habits[0].attribute = u.fns.randomVal({
|
||||||
|
str: 'str',
|
||||||
|
int: 'int',
|
||||||
|
per: 'per',
|
||||||
|
con: 'con'
|
||||||
|
});
|
||||||
|
u.ops.score({
|
||||||
|
params: {
|
||||||
|
id: u.habits[0].id
|
||||||
|
},
|
||||||
|
direction: 'up'
|
||||||
|
});
|
||||||
|
u.fns.updateStats(u.stats);
|
||||||
|
str = mode + (mode === 'taskbased' ? " (" + u.habits[0].attribute + ")" : "");
|
||||||
|
return console.log(str, _.pick(u.stats, $w('per int con str')));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
}).call(this);
|
||||||
@@ -1,180 +0,0 @@
|
|||||||
###
|
|
||||||
1) clone the repo
|
|
||||||
2) npm install
|
|
||||||
3) coffee ./tests/math_samples.coffee
|
|
||||||
|
|
||||||
Current results at https://gist.github.com/lefnire/8049676
|
|
||||||
###
|
|
||||||
|
|
||||||
shared = require '../../../common/script/index.js'
|
|
||||||
_ = require 'lodash'
|
|
||||||
|
|
||||||
id = shared.uuid()
|
|
||||||
user =
|
|
||||||
stats: {class: 'warrior', buffs: {per:0,int:0,con:0,str:0}}
|
|
||||||
party: quest: key:'evilsanta', progress: {up:0,down:0}
|
|
||||||
preferences: automaticAllocation:false
|
|
||||||
achievements:{}
|
|
||||||
flags: levelDrops: {}
|
|
||||||
items:
|
|
||||||
eggs: {}
|
|
||||||
hatchingPotions: {}
|
|
||||||
food: {}
|
|
||||||
quests:{}
|
|
||||||
gear:
|
|
||||||
equipped:
|
|
||||||
weapon: 'weapon_warrior_4'
|
|
||||||
armor: 'armor_warrior_4'
|
|
||||||
shield: 'shield_warrior_4'
|
|
||||||
head: 'head_warrior_4'
|
|
||||||
habits: [
|
|
||||||
shared.taskDefaults({id, value: 0})
|
|
||||||
]
|
|
||||||
dailys: [{"text" : "1",},{"text" : "1",},{"text" : "1",},{"text" : "1",},{"text" : "1",},{"text" : "1",},{"text" : "1",},{"text" : "1",},{"text" : "1",},{"text" : "1",},{"text" : "1",},{"text" : "1",},{"text" : "1",},{"text" : "1",},{"text" : "1",}],
|
|
||||||
todos: []
|
|
||||||
rewards: []
|
|
||||||
|
|
||||||
shared.wrap(user)
|
|
||||||
s = user.stats
|
|
||||||
task = user.tasks[id]
|
|
||||||
party = [user]
|
|
||||||
|
|
||||||
console.log "\n\n================================================"
|
|
||||||
console.log "New Simulation"
|
|
||||||
console.log "================================================\n\n"
|
|
||||||
|
|
||||||
clearUser = (lvl=1) ->
|
|
||||||
_.merge user.stats, {exp:0, gp:0, hp:50, lvl:lvl, str:lvl*1.5, con:lvl*1.5, per:lvl*1.5, int:lvl*1.5, mp: 100}
|
|
||||||
_.merge s.buffs, {str:0,con:0,int:0,per:0}
|
|
||||||
_.merge user.party.quest.progress, {up:0,down:0}
|
|
||||||
user.items.lastDrop = {count:0}
|
|
||||||
|
|
||||||
_.each [1,25,50,75,100], (lvl) ->
|
|
||||||
console.log "[LEVEL #{lvl}] (#{lvl*2} points total in every attr)\n\n"
|
|
||||||
_.each {red:-25,yellow:0,green:35}, (taskVal, color) ->
|
|
||||||
console.log "[task.value = #{taskVal} (#{color})]"
|
|
||||||
console.log "direction\texpΔ\t\thpΔ\tgpΔ\ttask.valΔ\ttask.valΔ bonus\t\tboss-hit"
|
|
||||||
_.each ['up','down'], (direction) ->
|
|
||||||
clearUser(lvl)
|
|
||||||
b4 = {hp:s.hp, taskVal}
|
|
||||||
task.value = taskVal
|
|
||||||
task.type = 'daily' if direction is 'up'
|
|
||||||
delta = user.ops.score params:{id, direction}
|
|
||||||
console.log "#{if direction is 'up' then '↑' else '↓'}\t\t#{s.exp}/#{shared.tnl(s.lvl)}\t\t#{(b4.hp-s.hp).toFixed(1)}\t#{s.gp.toFixed(1)}\t#{delta.toFixed(1)}\t\t#{(task.value-b4.taskVal-delta).toFixed(1)}\t\t\t#{user.party.quest.progress.up.toFixed(1)}"
|
|
||||||
|
|
||||||
str = '- [Wizard]'
|
|
||||||
|
|
||||||
task.value = taskVal;clearUser(lvl)
|
|
||||||
b4 = {taskVal}
|
|
||||||
shared.content.spells.wizard.fireball.cast(user,task)
|
|
||||||
str += "\tfireball(task.valΔ:#{(task.value-taskVal).toFixed(1)} exp:#{s.exp.toFixed(1)} bossHit:#{user.party.quest.progress.up.toFixed(2)})"
|
|
||||||
|
|
||||||
task.value = taskVal;clearUser(lvl)
|
|
||||||
_party = [user, {stats:{mp:0}}]
|
|
||||||
shared.content.spells.wizard.mpheal.cast(user,_party)
|
|
||||||
str += "\t| mpheal(mp:#{_party[1].stats.mp})"
|
|
||||||
|
|
||||||
task.value = taskVal;clearUser(lvl)
|
|
||||||
shared.content.spells.wizard.earth.cast(user,party)
|
|
||||||
str += "\t\t\t\t| earth(buffs.int:#{s.buffs.int})"
|
|
||||||
s.buffs.int = 0
|
|
||||||
|
|
||||||
task.value = taskVal;clearUser(lvl)
|
|
||||||
shared.content.spells.wizard.frost.cast(user,{})
|
|
||||||
str += "\t\t\t| frost(N/A)"
|
|
||||||
|
|
||||||
console.log str
|
|
||||||
str = '- [Warrior]'
|
|
||||||
|
|
||||||
task.value = taskVal;clearUser(lvl)
|
|
||||||
shared.content.spells.warrior.smash.cast(user,task)
|
|
||||||
b4 = {taskVal}
|
|
||||||
str += "\tsmash(task.valΔ:#{(task.value-taskVal).toFixed(1)})"
|
|
||||||
|
|
||||||
task.value = taskVal;clearUser(lvl)
|
|
||||||
shared.content.spells.warrior.defensiveStance.cast(user,{})
|
|
||||||
str += "\t\t| defensiveStance(buffs.con:#{s.buffs.con})"
|
|
||||||
s.buffs.con = 0
|
|
||||||
|
|
||||||
task.value = taskVal;clearUser(lvl)
|
|
||||||
shared.content.spells.warrior.valorousPresence.cast(user,party)
|
|
||||||
str += "\t\t\t| valorousPresence(buffs.str:#{s.buffs.str})"
|
|
||||||
s.buffs.str = 0
|
|
||||||
|
|
||||||
task.value = taskVal;clearUser(lvl)
|
|
||||||
shared.content.spells.warrior.intimidate.cast(user,party)
|
|
||||||
str += "\t\t| intimidate(buffs.con:#{s.buffs.con})"
|
|
||||||
s.buffs.con = 0
|
|
||||||
|
|
||||||
console.log str
|
|
||||||
str = '- [Rogue]'
|
|
||||||
|
|
||||||
task.value = taskVal;clearUser(lvl)
|
|
||||||
shared.content.spells.rogue.pickPocket.cast(user,task)
|
|
||||||
str += "\tpickPocket(gp:#{s.gp.toFixed(1)})"
|
|
||||||
|
|
||||||
task.value = taskVal;clearUser(lvl)
|
|
||||||
shared.content.spells.rogue.backStab.cast(user,task)
|
|
||||||
b4 = {taskVal}
|
|
||||||
str += "\t\t| backStab(task.valΔ:#{(task.value-b4.taskVal).toFixed(1)} exp:#{s.exp.toFixed(1)} gp:#{s.gp.toFixed(1)})"
|
|
||||||
|
|
||||||
task.value = taskVal;clearUser(lvl)
|
|
||||||
shared.content.spells.rogue.toolsOfTrade.cast(user,party)
|
|
||||||
str += "\t| toolsOfTrade(buffs.per:#{s.buffs.per})"
|
|
||||||
s.buffs.per = 0
|
|
||||||
|
|
||||||
task.value = taskVal;clearUser(lvl)
|
|
||||||
shared.content.spells.rogue.stealth.cast(user,{})
|
|
||||||
str += "\t\t| stealth(avoiding #{user.stats.buffs.stealth} tasks)"
|
|
||||||
user.stats.buffs.stealth = 0
|
|
||||||
|
|
||||||
console.log str
|
|
||||||
str = '- [Healer]'
|
|
||||||
|
|
||||||
task.value = taskVal;clearUser(lvl)
|
|
||||||
s.hp=0
|
|
||||||
shared.content.spells.healer.heal.cast(user,{})
|
|
||||||
str += "\theal(hp:#{s.hp.toFixed(1)})"
|
|
||||||
|
|
||||||
task.value = taskVal;clearUser(lvl)
|
|
||||||
shared.content.spells.healer.brightness.cast(user,{})
|
|
||||||
b4 = {taskVal}
|
|
||||||
str += "\t\t\t| brightness(task.valΔ:#{(task.value-b4.taskVal).toFixed(1)})"
|
|
||||||
|
|
||||||
task.value = taskVal;clearUser(lvl)
|
|
||||||
shared.content.spells.healer.protectAura.cast(user,party)
|
|
||||||
str += "\t\t\t| protectAura(buffs.con:#{s.buffs.con})"
|
|
||||||
s.buffs.con = 0
|
|
||||||
|
|
||||||
task.value = taskVal;clearUser(lvl)
|
|
||||||
s.hp=0
|
|
||||||
shared.content.spells.healer.heallAll.cast(user,party)
|
|
||||||
str += "\t\t| heallAll(hp:#{s.hp.toFixed(1)})"
|
|
||||||
|
|
||||||
console.log str
|
|
||||||
console.log '\n'
|
|
||||||
|
|
||||||
|
|
||||||
console.log '------------------------------------------------------------'
|
|
||||||
|
|
||||||
###
|
|
||||||
_.each [1,25,50,75,100,125], (lvl) ->
|
|
||||||
console.log "[LEVEL #{lvl}] (#{lvl*2} points in every attr)\n\n"
|
|
||||||
_.each {red:-25,yellow:0,green:35}, (taskVal, color) ->
|
|
||||||
console.log "[task.value = #{taskVal} (#{color})]"
|
|
||||||
console.log "direction\texpΔ\t\thpΔ\tgpΔ\ttask.valΔ\ttask.valΔ bonus\t\tboss-hit"
|
|
||||||
_.each ['up','down'], (direction) ->
|
|
||||||
clearUser(lvl)
|
|
||||||
b4 = {hp:s.hp, taskVal}
|
|
||||||
task.value = taskVal
|
|
||||||
task.type = 'daily' if direction is 'up'
|
|
||||||
delta = user.ops.score params:{id, direction}
|
|
||||||
console.log "#{if direction is 'up' then '↑' else '↓'}\t\t#{s.exp}/#{shared.tnl(s.lvl)}\t\t#{(b4.hp-s.hp).toFixed(1)}\t#{s.gp.toFixed(1)}\t#{delta.toFixed(1)}\t\t#{(task.value-b4.taskVal-delta).toFixed(1)}\t\t\t#{user.party.quest.progress.up.toFixed(1)}"
|
|
||||||
|
|
||||||
task.value = taskVal;clearUser(lvl)
|
|
||||||
shared.content.spells.rogue.stealth.cast(user,{})
|
|
||||||
console.log "\t\t| stealth(avoiding #{user.stats.buffs.stealth} tasks)"
|
|
||||||
user.stats.buffs.stealth = 0
|
|
||||||
|
|
||||||
console.log user.dailys.length
|
|
||||||
###
|
|
||||||
294
test/common/simulations/passive_active_attrs.js
Normal file
294
test/common/simulations/passive_active_attrs.js
Normal file
@@ -0,0 +1,294 @@
|
|||||||
|
(function() {
|
||||||
|
var _, clearUser, id, party, s, shared, task, user;
|
||||||
|
|
||||||
|
shared = require('../../../common/script/index.js');
|
||||||
|
|
||||||
|
_ = require('lodash');
|
||||||
|
|
||||||
|
id = shared.uuid();
|
||||||
|
|
||||||
|
user = {
|
||||||
|
stats: {
|
||||||
|
"class": 'warrior',
|
||||||
|
buffs: {
|
||||||
|
per: 0,
|
||||||
|
int: 0,
|
||||||
|
con: 0,
|
||||||
|
str: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
party: {
|
||||||
|
quest: {
|
||||||
|
key: 'evilsanta',
|
||||||
|
progress: {
|
||||||
|
up: 0,
|
||||||
|
down: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
preferences: {
|
||||||
|
automaticAllocation: false
|
||||||
|
},
|
||||||
|
achievements: {},
|
||||||
|
flags: {
|
||||||
|
levelDrops: {}
|
||||||
|
},
|
||||||
|
items: {
|
||||||
|
eggs: {},
|
||||||
|
hatchingPotions: {},
|
||||||
|
food: {},
|
||||||
|
quests: {},
|
||||||
|
gear: {
|
||||||
|
equipped: {
|
||||||
|
weapon: 'weapon_warrior_4',
|
||||||
|
armor: 'armor_warrior_4',
|
||||||
|
shield: 'shield_warrior_4',
|
||||||
|
head: 'head_warrior_4'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
habits: [
|
||||||
|
shared.taskDefaults({
|
||||||
|
id: id,
|
||||||
|
value: 0
|
||||||
|
})
|
||||||
|
],
|
||||||
|
dailys: [
|
||||||
|
{
|
||||||
|
"text": "1"
|
||||||
|
}, {
|
||||||
|
"text": "1"
|
||||||
|
}, {
|
||||||
|
"text": "1"
|
||||||
|
}, {
|
||||||
|
"text": "1"
|
||||||
|
}, {
|
||||||
|
"text": "1"
|
||||||
|
}, {
|
||||||
|
"text": "1"
|
||||||
|
}, {
|
||||||
|
"text": "1"
|
||||||
|
}, {
|
||||||
|
"text": "1"
|
||||||
|
}, {
|
||||||
|
"text": "1"
|
||||||
|
}, {
|
||||||
|
"text": "1"
|
||||||
|
}, {
|
||||||
|
"text": "1"
|
||||||
|
}, {
|
||||||
|
"text": "1"
|
||||||
|
}, {
|
||||||
|
"text": "1"
|
||||||
|
}, {
|
||||||
|
"text": "1"
|
||||||
|
}, {
|
||||||
|
"text": "1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
todos: [],
|
||||||
|
rewards: []
|
||||||
|
};
|
||||||
|
|
||||||
|
shared.wrap(user);
|
||||||
|
|
||||||
|
s = user.stats;
|
||||||
|
|
||||||
|
task = user.tasks[id];
|
||||||
|
|
||||||
|
party = [user];
|
||||||
|
|
||||||
|
console.log("\n\n================================================");
|
||||||
|
|
||||||
|
console.log("New Simulation");
|
||||||
|
|
||||||
|
console.log("================================================\n\n");
|
||||||
|
|
||||||
|
clearUser = function(lvl) {
|
||||||
|
if (lvl == null) {
|
||||||
|
lvl = 1;
|
||||||
|
}
|
||||||
|
_.merge(user.stats, {
|
||||||
|
exp: 0,
|
||||||
|
gp: 0,
|
||||||
|
hp: 50,
|
||||||
|
lvl: lvl,
|
||||||
|
str: lvl * 1.5,
|
||||||
|
con: lvl * 1.5,
|
||||||
|
per: lvl * 1.5,
|
||||||
|
int: lvl * 1.5,
|
||||||
|
mp: 100
|
||||||
|
});
|
||||||
|
_.merge(s.buffs, {
|
||||||
|
str: 0,
|
||||||
|
con: 0,
|
||||||
|
int: 0,
|
||||||
|
per: 0
|
||||||
|
});
|
||||||
|
_.merge(user.party.quest.progress, {
|
||||||
|
up: 0,
|
||||||
|
down: 0
|
||||||
|
});
|
||||||
|
return user.items.lastDrop = {
|
||||||
|
count: 0
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
_.each([1, 25, 50, 75, 100], function(lvl) {
|
||||||
|
console.log("[LEVEL " + lvl + "] (" + (lvl * 2) + " points total in every attr)\n\n");
|
||||||
|
_.each({
|
||||||
|
red: -25,
|
||||||
|
yellow: 0,
|
||||||
|
green: 35
|
||||||
|
}, function(taskVal, color) {
|
||||||
|
var _party, b4, str;
|
||||||
|
console.log("[task.value = " + taskVal + " (" + color + ")]");
|
||||||
|
console.log("direction\texpΔ\t\thpΔ\tgpΔ\ttask.valΔ\ttask.valΔ bonus\t\tboss-hit");
|
||||||
|
_.each(['up', 'down'], function(direction) {
|
||||||
|
var b4, delta;
|
||||||
|
clearUser(lvl);
|
||||||
|
b4 = {
|
||||||
|
hp: s.hp,
|
||||||
|
taskVal: taskVal
|
||||||
|
};
|
||||||
|
task.value = taskVal;
|
||||||
|
if (direction === 'up') {
|
||||||
|
task.type = 'daily';
|
||||||
|
}
|
||||||
|
delta = user.ops.score({
|
||||||
|
params: {
|
||||||
|
id: id,
|
||||||
|
direction: direction
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return console.log((direction === 'up' ? '↑' : '↓') + "\t\t" + s.exp + "/" + (shared.tnl(s.lvl)) + "\t\t" + ((b4.hp - s.hp).toFixed(1)) + "\t" + (s.gp.toFixed(1)) + "\t" + (delta.toFixed(1)) + "\t\t" + ((task.value - b4.taskVal - delta).toFixed(1)) + "\t\t\t" + (user.party.quest.progress.up.toFixed(1)));
|
||||||
|
});
|
||||||
|
str = '- [Wizard]';
|
||||||
|
task.value = taskVal;
|
||||||
|
clearUser(lvl);
|
||||||
|
b4 = {
|
||||||
|
taskVal: taskVal
|
||||||
|
};
|
||||||
|
shared.content.spells.wizard.fireball.cast(user, task);
|
||||||
|
str += "\tfireball(task.valΔ:" + ((task.value - taskVal).toFixed(1)) + " exp:" + (s.exp.toFixed(1)) + " bossHit:" + (user.party.quest.progress.up.toFixed(2)) + ")";
|
||||||
|
task.value = taskVal;
|
||||||
|
clearUser(lvl);
|
||||||
|
_party = [
|
||||||
|
user, {
|
||||||
|
stats: {
|
||||||
|
mp: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
shared.content.spells.wizard.mpheal.cast(user, _party);
|
||||||
|
str += "\t| mpheal(mp:" + _party[1].stats.mp + ")";
|
||||||
|
task.value = taskVal;
|
||||||
|
clearUser(lvl);
|
||||||
|
shared.content.spells.wizard.earth.cast(user, party);
|
||||||
|
str += "\t\t\t\t| earth(buffs.int:" + s.buffs.int + ")";
|
||||||
|
s.buffs.int = 0;
|
||||||
|
task.value = taskVal;
|
||||||
|
clearUser(lvl);
|
||||||
|
shared.content.spells.wizard.frost.cast(user, {});
|
||||||
|
str += "\t\t\t| frost(N/A)";
|
||||||
|
console.log(str);
|
||||||
|
str = '- [Warrior]';
|
||||||
|
task.value = taskVal;
|
||||||
|
clearUser(lvl);
|
||||||
|
shared.content.spells.warrior.smash.cast(user, task);
|
||||||
|
b4 = {
|
||||||
|
taskVal: taskVal
|
||||||
|
};
|
||||||
|
str += "\tsmash(task.valΔ:" + ((task.value - taskVal).toFixed(1)) + ")";
|
||||||
|
task.value = taskVal;
|
||||||
|
clearUser(lvl);
|
||||||
|
shared.content.spells.warrior.defensiveStance.cast(user, {});
|
||||||
|
str += "\t\t| defensiveStance(buffs.con:" + s.buffs.con + ")";
|
||||||
|
s.buffs.con = 0;
|
||||||
|
task.value = taskVal;
|
||||||
|
clearUser(lvl);
|
||||||
|
shared.content.spells.warrior.valorousPresence.cast(user, party);
|
||||||
|
str += "\t\t\t| valorousPresence(buffs.str:" + s.buffs.str + ")";
|
||||||
|
s.buffs.str = 0;
|
||||||
|
task.value = taskVal;
|
||||||
|
clearUser(lvl);
|
||||||
|
shared.content.spells.warrior.intimidate.cast(user, party);
|
||||||
|
str += "\t\t| intimidate(buffs.con:" + s.buffs.con + ")";
|
||||||
|
s.buffs.con = 0;
|
||||||
|
console.log(str);
|
||||||
|
str = '- [Rogue]';
|
||||||
|
task.value = taskVal;
|
||||||
|
clearUser(lvl);
|
||||||
|
shared.content.spells.rogue.pickPocket.cast(user, task);
|
||||||
|
str += "\tpickPocket(gp:" + (s.gp.toFixed(1)) + ")";
|
||||||
|
task.value = taskVal;
|
||||||
|
clearUser(lvl);
|
||||||
|
shared.content.spells.rogue.backStab.cast(user, task);
|
||||||
|
b4 = {
|
||||||
|
taskVal: taskVal
|
||||||
|
};
|
||||||
|
str += "\t\t| backStab(task.valΔ:" + ((task.value - b4.taskVal).toFixed(1)) + " exp:" + (s.exp.toFixed(1)) + " gp:" + (s.gp.toFixed(1)) + ")";
|
||||||
|
task.value = taskVal;
|
||||||
|
clearUser(lvl);
|
||||||
|
shared.content.spells.rogue.toolsOfTrade.cast(user, party);
|
||||||
|
str += "\t| toolsOfTrade(buffs.per:" + s.buffs.per + ")";
|
||||||
|
s.buffs.per = 0;
|
||||||
|
task.value = taskVal;
|
||||||
|
clearUser(lvl);
|
||||||
|
shared.content.spells.rogue.stealth.cast(user, {});
|
||||||
|
str += "\t\t| stealth(avoiding " + user.stats.buffs.stealth + " tasks)";
|
||||||
|
user.stats.buffs.stealth = 0;
|
||||||
|
console.log(str);
|
||||||
|
str = '- [Healer]';
|
||||||
|
task.value = taskVal;
|
||||||
|
clearUser(lvl);
|
||||||
|
s.hp = 0;
|
||||||
|
shared.content.spells.healer.heal.cast(user, {});
|
||||||
|
str += "\theal(hp:" + (s.hp.toFixed(1)) + ")";
|
||||||
|
task.value = taskVal;
|
||||||
|
clearUser(lvl);
|
||||||
|
shared.content.spells.healer.brightness.cast(user, {});
|
||||||
|
b4 = {
|
||||||
|
taskVal: taskVal
|
||||||
|
};
|
||||||
|
str += "\t\t\t| brightness(task.valΔ:" + ((task.value - b4.taskVal).toFixed(1)) + ")";
|
||||||
|
task.value = taskVal;
|
||||||
|
clearUser(lvl);
|
||||||
|
shared.content.spells.healer.protectAura.cast(user, party);
|
||||||
|
str += "\t\t\t| protectAura(buffs.con:" + s.buffs.con + ")";
|
||||||
|
s.buffs.con = 0;
|
||||||
|
task.value = taskVal;
|
||||||
|
clearUser(lvl);
|
||||||
|
s.hp = 0;
|
||||||
|
shared.content.spells.healer.heallAll.cast(user, party);
|
||||||
|
str += "\t\t| heallAll(hp:" + (s.hp.toFixed(1)) + ")";
|
||||||
|
console.log(str);
|
||||||
|
return console.log('\n');
|
||||||
|
});
|
||||||
|
return console.log('------------------------------------------------------------');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
_.each [1,25,50,75,100,125], (lvl) ->
|
||||||
|
console.log "[LEVEL #{lvl}] (#{lvl*2} points in every attr)\n\n"
|
||||||
|
_.each {red:-25,yellow:0,green:35}, (taskVal, color) ->
|
||||||
|
console.log "[task.value = #{taskVal} (#{color})]"
|
||||||
|
console.log "direction\texpΔ\t\thpΔ\tgpΔ\ttask.valΔ\ttask.valΔ bonus\t\tboss-hit"
|
||||||
|
_.each ['up','down'], (direction) ->
|
||||||
|
clearUser(lvl)
|
||||||
|
b4 = {hp:s.hp, taskVal}
|
||||||
|
task.value = taskVal
|
||||||
|
task.type = 'daily' if direction is 'up'
|
||||||
|
delta = user.ops.score params:{id, direction}
|
||||||
|
console.log "#{if direction is 'up' then '↑' else '↓'}\t\t#{s.exp}/#{shared.tnl(s.lvl)}\t\t#{(b4.hp-s.hp).toFixed(1)}\t#{s.gp.toFixed(1)}\t#{delta.toFixed(1)}\t\t#{(task.value-b4.taskVal-delta).toFixed(1)}\t\t\t#{user.party.quest.progress.up.toFixed(1)}"
|
||||||
|
|
||||||
|
task.value = taskVal;clearUser(lvl)
|
||||||
|
shared.content.spells.rogue.stealth.cast(user,{})
|
||||||
|
console.log "\t\t| stealth(avoiding #{user.stats.buffs.stealth} tasks)"
|
||||||
|
user.stats.buffs.stealth = 0
|
||||||
|
|
||||||
|
console.log user.dailys.length
|
||||||
|
*/
|
||||||
|
|
||||||
|
}).call(this);
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
expect = require 'expect.js'
|
|
||||||
|
|
||||||
module.exports.addCustomMatchers = ->
|
|
||||||
Assertion = expect.Assertion
|
|
||||||
|
|
||||||
Assertion.prototype.toHaveGP = (gp)->
|
|
||||||
actual = @obj.stats.gp
|
|
||||||
@assert(
|
|
||||||
actual == gp,
|
|
||||||
-> "expected user to have #{gp} gp, but got #{actual}",
|
|
||||||
-> "expected user to not have #{gp} gp"
|
|
||||||
)
|
|
||||||
|
|
||||||
Assertion.prototype.toHaveHP = (hp)->
|
|
||||||
actual = @obj.stats.hp
|
|
||||||
@assert(
|
|
||||||
actual == hp,
|
|
||||||
-> "expected user to have #{hp} hp, but got #{actual}",
|
|
||||||
-> "expected user to not have #{hp} hp"
|
|
||||||
)
|
|
||||||
|
|
||||||
Assertion.prototype.toHaveExp = (exp)->
|
|
||||||
actual = @obj.stats.exp
|
|
||||||
@assert(
|
|
||||||
actual == exp,
|
|
||||||
-> "expected user to have #{exp} experience points, but got #{actual}",
|
|
||||||
-> "expected user to not have #{exp} experience points"
|
|
||||||
)
|
|
||||||
|
|
||||||
Assertion.prototype.toHaveLevel = (lvl)->
|
|
||||||
actual = @obj.stats.lvl
|
|
||||||
@assert(
|
|
||||||
actual == lvl,
|
|
||||||
-> "expected user to be level #{lvl}, but got #{actual}",
|
|
||||||
-> "expected user to not be level #{lvl}"
|
|
||||||
)
|
|
||||||
|
|
||||||
Assertion.prototype.toHaveMaxMP = (mp)->
|
|
||||||
actual = @obj._statsComputed.maxMP
|
|
||||||
@assert(
|
|
||||||
actual == mp,
|
|
||||||
-> "expected user to have #{mp} max mp, but got #{actual}",
|
|
||||||
-> "expected user to not have #{mp} max mp"
|
|
||||||
)
|
|
||||||
53
test/common/test_helper.js
Normal file
53
test/common/test_helper.js
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
var expect;
|
||||||
|
|
||||||
|
expect = require('expect.js');
|
||||||
|
|
||||||
|
module.exports.addCustomMatchers = function() {
|
||||||
|
var Assertion;
|
||||||
|
Assertion = expect.Assertion;
|
||||||
|
Assertion.prototype.toHaveGP = function(gp) {
|
||||||
|
var actual;
|
||||||
|
actual = this.obj.stats.gp;
|
||||||
|
return this.assert(actual === gp, function() {
|
||||||
|
return "expected user to have " + gp + " gp, but got " + actual;
|
||||||
|
}, function() {
|
||||||
|
return "expected user to not have " + gp + " gp";
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Assertion.prototype.toHaveHP = function(hp) {
|
||||||
|
var actual;
|
||||||
|
actual = this.obj.stats.hp;
|
||||||
|
return this.assert(actual === hp, function() {
|
||||||
|
return "expected user to have " + hp + " hp, but got " + actual;
|
||||||
|
}, function() {
|
||||||
|
return "expected user to not have " + hp + " hp";
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Assertion.prototype.toHaveExp = function(exp) {
|
||||||
|
var actual;
|
||||||
|
actual = this.obj.stats.exp;
|
||||||
|
return this.assert(actual === exp, function() {
|
||||||
|
return "expected user to have " + exp + " experience points, but got " + actual;
|
||||||
|
}, function() {
|
||||||
|
return "expected user to not have " + exp + " experience points";
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Assertion.prototype.toHaveLevel = function(lvl) {
|
||||||
|
var actual;
|
||||||
|
actual = this.obj.stats.lvl;
|
||||||
|
return this.assert(actual === lvl, function() {
|
||||||
|
return "expected user to be level " + lvl + ", but got " + actual;
|
||||||
|
}, function() {
|
||||||
|
return "expected user to not be level " + lvl;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
return Assertion.prototype.toHaveMaxMP = function(mp) {
|
||||||
|
var actual;
|
||||||
|
actual = this.obj._statsComputed.maxMP;
|
||||||
|
return this.assert(actual === mp, function() {
|
||||||
|
return "expected user to have " + mp + " max mp, but got " + actual;
|
||||||
|
}, function() {
|
||||||
|
return "expected user to not have " + mp + " max mp";
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user