mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-18 07:07:35 +01:00
don't need public/private paths after all, can check path requests in store accessControl callbacks
This commit is contained in:
@@ -52,42 +52,40 @@ db.users.find().forEach(function(user){
|
||||
// Note 'public' and 'private' are reserved words
|
||||
var newUser = {
|
||||
auth: user.auth, // we need this top-level due to derby-auth
|
||||
pub:{
|
||||
party: null,
|
||||
invitations: [],
|
||||
items: {
|
||||
armor: user.items.armor || 0,
|
||||
weapon: user.items.weapon || 0
|
||||
apiToken: user.preferences.api_token || null, // set on update, we need derby.uuid()
|
||||
preferences: {
|
||||
armorSet: user.preferences.armorSet || 'v1',
|
||||
gender: user.preferences.gender || 'm'
|
||||
},
|
||||
balance: user.balance || 2,
|
||||
lastCron: user.lastCron || +new Date,
|
||||
history: user.history || [],
|
||||
stats: {
|
||||
gp: user.stats.money || 0,
|
||||
hp: user.stats.hp || 50,
|
||||
exp: user.stats.exp || 0,
|
||||
lvl: user.stats.lvl || 1
|
||||
},
|
||||
preferences: {
|
||||
armorSet: user.preferences.armorSet || 'v1',
|
||||
gender: user.preferences.gender || 'm'
|
||||
}
|
||||
items: {
|
||||
armor: user.items.armor || 0,
|
||||
weapon: user.items.weapon || 0
|
||||
},
|
||||
priv: {
|
||||
balance: user.balance || 2,
|
||||
lastCron: user.lastCron || +new Date,
|
||||
tasks: user.tasks || {},
|
||||
history: user.history || [],
|
||||
apiToken: user.preferences.api_token || null, // set on update, we need derby.uuid()
|
||||
idLists: {
|
||||
habit:user.habitList || [],
|
||||
daily:user.dailyList || [],
|
||||
todo:user.todoList || [],
|
||||
reward:user.rewardList || []
|
||||
habit: user.habitIds || [],
|
||||
daily: user.dailyIds || [],
|
||||
todo: user.todoIds || [],
|
||||
reward: user.rewardIds || []
|
||||
},
|
||||
flags: {
|
||||
partyEnabled: false,
|
||||
itemsEnabled: user.items.itemsEnabled || false,
|
||||
kickstarter: user.notifications.kickstarter || 'show',
|
||||
ads: user.flags.ads || null // null because it's set on registration
|
||||
}
|
||||
},
|
||||
party: {
|
||||
current: null,
|
||||
invitation: null
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ module.exports.setupGrowlNotifications = (model) ->
|
||||
|
||||
statsNotification = (html, type) ->
|
||||
#don't show notifications if user dead
|
||||
return if user.get('pub.stats.lvl') == 0
|
||||
return if user.get('stats.lvl') == 0
|
||||
$.bootstrapGrowl html,
|
||||
type: type # (null, 'info', 'error', 'success')
|
||||
top_offset: 20
|
||||
@@ -95,7 +95,7 @@ module.exports.setupGrowlNotifications = (model) ->
|
||||
allow_dismiss: true
|
||||
stackup_spacing: 10 # spacing between consecutive stacecked growls.
|
||||
|
||||
user.on 'set', 'priv.flags.itemsEnabled', (captures, args) ->
|
||||
user.on 'set', 'flags.itemsEnabled', (captures, args) ->
|
||||
return unless captures == true
|
||||
message = "Congratulations, you have unlocked the Item Store! You can now buy weapons, armor, potions, etc. Read each item's comment for more information."
|
||||
$('ul.items').popover
|
||||
@@ -109,7 +109,7 @@ module.exports.setupGrowlNotifications = (model) ->
|
||||
</div>"
|
||||
$('ul.items').popover 'show'
|
||||
|
||||
user.on 'set', 'priv.flags.partyEnabled', (captures, args) ->
|
||||
user.on 'set', 'flags.partyEnabled', (captures, args) ->
|
||||
return unless captures == true
|
||||
message = "Congratulations, you have unlocked the Party System! You can now group with your friends by adding their User Ids."
|
||||
$('#add-party-button').popover
|
||||
@@ -125,13 +125,13 @@ module.exports.setupGrowlNotifications = (model) ->
|
||||
|
||||
|
||||
# Setup listeners which trigger notifications
|
||||
user.on 'set', 'pub.stats.hp', (captures, args) ->
|
||||
user.on 'set', 'stats.hp', (captures, args) ->
|
||||
num = captures - args
|
||||
rounded = Math.abs(num.toFixed(1))
|
||||
if num < 0
|
||||
statsNotification "<i class='icon-heart'></i>HP -#{rounded}", 'error' # lost hp from purchase
|
||||
|
||||
user.on 'set', 'pub.stats.gp', (captures, args) ->
|
||||
user.on 'set', 'stats.gp', (captures, args) ->
|
||||
num = captures - args
|
||||
rounded = Math.abs(num.toFixed(1))
|
||||
# made purchase
|
||||
@@ -143,6 +143,6 @@ module.exports.setupGrowlNotifications = (model) ->
|
||||
num = Math.abs(num)
|
||||
statsNotification "<i class='icon-star'></i>Exp,GP +#{rounded}", 'success'
|
||||
|
||||
user.on 'set', 'pub.stats.lvl', (captures, args) ->
|
||||
user.on 'set', 'stats.lvl', (captures, args) ->
|
||||
if captures > args
|
||||
statsNotification('<i class="icon-chevron-up"></i> Level Up!', 'info')
|
||||
@@ -57,9 +57,9 @@ module.exports.viewHelpers = (view) ->
|
||||
return gp/0.25
|
||||
|
||||
view.fn 'currentArmor', (user) ->
|
||||
user = { pub:{ items: {armor:0}, preferences: {gender:'m', armorSet:'v1'}}} unless user?
|
||||
armor = user.pub.items.armor
|
||||
{gender, armorSet} = user.pub.items
|
||||
user = { items: {armor:0}, preferences: {gender:'m', armorSet:'v1'}} unless user?
|
||||
armor = user.items.armor
|
||||
{gender, armorSet} = user.preferences
|
||||
if gender == 'f'
|
||||
str = "armor#{armor}_f"
|
||||
if parseInt(armor) > 1
|
||||
|
||||
@@ -16,10 +16,10 @@ _ = require('underscore')
|
||||
|
||||
setupListReferences = (model) ->
|
||||
taskTypes = ['habit', 'daily', 'todo', 'reward']
|
||||
_.each taskTypes, (type) -> model.refList "_#{type}List", "_user.priv.tasks", "_user.priv.idLists.#{type}"
|
||||
_.each taskTypes, (type) -> model.refList "_#{type}List", "_user.tasks", "_user.idLists.#{type}"
|
||||
|
||||
setupModelFns = (model) ->
|
||||
model.fn '_tnl', '_user.pub.stats.lvl', (lvl) ->
|
||||
model.fn '_tnl', '_user.stats.lvl', (lvl) ->
|
||||
# see https://github.com/lefnire/habitrpg/issues/4
|
||||
# also update in scoring.coffee. TODO create a function accessible in both locations
|
||||
(lvl*100)/5
|
||||
@@ -51,8 +51,8 @@ get '/', (page, model, next) ->
|
||||
|
||||
# Setup Item Store
|
||||
_view.items =
|
||||
armor: content.items.armor[parseInt(obj.pub.items?.armor || 0) + 1]
|
||||
weapon: content.items.weapon[parseInt(obj.pub.items?.weapon || 0) + 1]
|
||||
armor: content.items.armor[parseInt(obj.items?.armor || 0) + 1]
|
||||
weapon: content.items.weapon[parseInt(obj.items?.weapon || 0) + 1]
|
||||
potion: content.items.potion
|
||||
reroll: content.items.reroll
|
||||
|
||||
@@ -65,8 +65,8 @@ get '/', (page, model, next) ->
|
||||
setupModelFns(model)
|
||||
|
||||
# Subscribe to friends
|
||||
if !_.isEmpty(obj.pub.party)
|
||||
model.subscribe model.query('users').party(obj.pub.party), (err, party) ->
|
||||
if !_.isEmpty(obj.party)
|
||||
model.subscribe model.query('users').party(obj.party), (err, party) ->
|
||||
model.ref '_party', party
|
||||
|
||||
page.render()
|
||||
@@ -83,8 +83,8 @@ ready (model) ->
|
||||
scoring.setModel(model)
|
||||
|
||||
#set cron immediately
|
||||
lastCron = user.get('priv.lastCron')
|
||||
user.set('priv.lastCron', +new Date) if (!lastCron? or lastCron == 'new')
|
||||
lastCron = user.get('lastCron')
|
||||
user.set('lastCron', +new Date) if (!lastCron? or lastCron == 'new')
|
||||
|
||||
# Setup model in scoring functions
|
||||
scoring.cron(resetDom)
|
||||
@@ -98,7 +98,7 @@ ready (model) ->
|
||||
|
||||
require('../server/private').app(exports, model)
|
||||
|
||||
user.on 'set', 'priv.tasks.*.completed', (i, completed, previous, isLocal, passed) ->
|
||||
user.on 'set', 'tasks.*.completed', (i, completed, previous, isLocal, passed) ->
|
||||
return if passed? && passed.cron # Don't do this stuff on cron
|
||||
direction = () ->
|
||||
return 'up' if completed==true and previous == false
|
||||
@@ -106,7 +106,7 @@ ready (model) ->
|
||||
throw new Error("Direction neither 'up' nor 'down' on checkbox set.")
|
||||
|
||||
# Score the user based on todo task
|
||||
task = user.at("priv.tasks.#{i}")
|
||||
task = user.at("tasks.#{i}")
|
||||
scoring.score(i, direction())
|
||||
|
||||
exports.addTask = (e, el, next) ->
|
||||
@@ -145,10 +145,10 @@ ready (model) ->
|
||||
id = $(e.target).parents('li.task').attr('data-id')
|
||||
return unless id?
|
||||
|
||||
task = user.at "priv.tasks.#{id}"
|
||||
task = user.at "tasks.#{id}"
|
||||
type = task.get('type')
|
||||
|
||||
history = task.get('priv.history')
|
||||
history = task.get('history')
|
||||
if history and history.length>2
|
||||
# prevent delete-and-recreate hack on red tasks
|
||||
if task.get('value') < 0
|
||||
@@ -168,22 +168,22 @@ ready (model) ->
|
||||
# fix when query subscriptions implemented properly
|
||||
$('[rel=tooltip]').tooltip('hide')
|
||||
|
||||
ids = user.get("priv.idLists.#{type}")
|
||||
ids = user.get("idLists.#{type}")
|
||||
ids.splice(ids.indexOf(id),1)
|
||||
user.del('priv.tasks.'+id)
|
||||
user.set("priv.idLists.#{type}", ids)
|
||||
user.del('tasks.'+id)
|
||||
user.set("idLists.#{type}", ids)
|
||||
|
||||
|
||||
exports.clearCompleted = (e, el) ->
|
||||
todoIds = user.get('priv.idLists.todo')
|
||||
todoIds = user.get('idLists.todo')
|
||||
removed = false
|
||||
_.each model.get('_todoList'), (task) ->
|
||||
if task.completed
|
||||
removed = true
|
||||
user.del('priv.tasks.'+task.id)
|
||||
user.del('tasks.'+task.id)
|
||||
todoIds.splice(todoIds.indexOf(task.id), 1)
|
||||
if removed
|
||||
user.set('priv.idLists.todo', todoIds)
|
||||
user.set('idLists.todo', todoIds)
|
||||
|
||||
exports.toggleDay = (e, el) ->
|
||||
task = model.at(e.target)
|
||||
@@ -226,22 +226,22 @@ ready (model) ->
|
||||
#TODO: this should be working but it's not. so instead, i'm passing all needed values as data-attrs
|
||||
# item = model.at(e.target)
|
||||
|
||||
gp = user.get 'pub.stats.gp'
|
||||
gp = user.get 'stats.gp'
|
||||
[type, value, index] = [ $(el).attr('data-type'), $(el).attr('data-value'), $(el).attr('data-index') ]
|
||||
|
||||
return if gp < value
|
||||
user.set 'pub.stats.gp', gp - value
|
||||
user.set 'stats.gp', gp - value
|
||||
if type == 'armor'
|
||||
user.set 'pub.items.armor', index
|
||||
user.set 'items.armor', index
|
||||
model.set '_view.items.armor', content.items.armor[parseInt(index) + 1]
|
||||
else if type == 'weapon'
|
||||
user.set 'pub.items.weapon', index
|
||||
user.set 'items.weapon', index
|
||||
model.set '_view.items.weapon', content.items.weapon[parseInt(index) + 1]
|
||||
else if type == 'potion'
|
||||
hp = user.get 'pub.stats.hp'
|
||||
hp = user.get 'stats.hp'
|
||||
hp += 15
|
||||
hp = 50 if hp > 50
|
||||
user.set 'pub.stats.hp', hp
|
||||
user.set 'stats.hp', hp
|
||||
|
||||
exports.score = (e, el, next) ->
|
||||
direction = $(el).attr('data-direction')
|
||||
@@ -252,14 +252,14 @@ ready (model) ->
|
||||
|
||||
revive = (batch) ->
|
||||
# Reset stats
|
||||
batch.set 'pub.stats.hp', 50
|
||||
batch.set 'pub.stats.lvl', 1
|
||||
batch.set 'pub.stats.gp', 0
|
||||
batch.set 'pub.stats.exp', 0
|
||||
batch.set 'stats.hp', 50
|
||||
batch.set 'stats.lvl', 1
|
||||
batch.set 'stats.gp', 0
|
||||
batch.set 'stats.exp', 0
|
||||
|
||||
# Reset items
|
||||
batch.set 'pub.items.armor', 0
|
||||
batch.set 'pub.items.weapon', 0
|
||||
batch.set 'items.armor', 0
|
||||
batch.set 'items.weapon', 0
|
||||
|
||||
# Reset item store
|
||||
model.set '_view.items.armor', content.items.armor[1]
|
||||
@@ -275,33 +275,33 @@ ready (model) ->
|
||||
batch = new schema.BatchUpdate(model)
|
||||
batch.startTransaction()
|
||||
taskTypes = ['habit', 'daily', 'todo', 'reward']
|
||||
batch.set 'priv.tasks', {}
|
||||
_.each taskTypes, (type) -> batch.set "priv.idLists.#{type}", []
|
||||
batch.set 'priv.balance', 2 if user.get('priv.balance') < 2 #only if they haven't manually bought tokens
|
||||
batch.set 'tasks', {}
|
||||
_.each taskTypes, (type) -> batch.set "idLists.#{type}", []
|
||||
batch.set 'balance', 2 if user.get('balance') < 2 #only if they haven't manually bought tokens
|
||||
revive(batch, true)
|
||||
batch.commit()
|
||||
resetDom(model)
|
||||
|
||||
exports.closeKickstarterNofitication = (e, el) ->
|
||||
user.set('priv.flags.kickstarter', 'hide')
|
||||
user.set('flags.kickstarter', 'hide')
|
||||
|
||||
exports.setMale = -> user.set('pub.preferences.gender', 'm')
|
||||
exports.setFemale = -> user.set('pub.preferences.gender', 'f')
|
||||
exports.setArmorsetV1 = -> user.set('pub.preferences.armorSet', 'v1')
|
||||
exports.setArmorsetV2 = -> user.set('pub.preferences.armorSet', 'v2')
|
||||
exports.setMale = -> user.set('preferences.gender', 'm')
|
||||
exports.setFemale = -> user.set('preferences.gender', 'f')
|
||||
exports.setArmorsetV1 = -> user.set('preferences.armorSet', 'v1')
|
||||
exports.setArmorsetV2 = -> user.set('preferences.armorSet', 'v2')
|
||||
|
||||
exports.addParty = ->
|
||||
id = model.get('_newPartyMember').replace(/[\s"]/g, '')
|
||||
debugger
|
||||
return if _.isEmpty(id)
|
||||
if user.get('pub.party').indexOf(id) != -1
|
||||
if user.get('party').indexOf(id) != -1
|
||||
model.set "_view.addPartyError", "#{id} already in party."
|
||||
return
|
||||
query = model.query('users').party([id])
|
||||
model.fetch query, (err, users) ->
|
||||
partyMember = users.at(0).get()
|
||||
if partyMember?.id?
|
||||
user.push('pub.party', id)
|
||||
user.push('party', id)
|
||||
$('#add-party-modal').modal('hide')
|
||||
window.location.reload() #TODO break old subscription, setup new subscript, remove this reload
|
||||
model.set '_newPartyMember', ''
|
||||
@@ -310,6 +310,6 @@ ready (model) ->
|
||||
|
||||
exports.emulateNextDay = ->
|
||||
yesterday = +moment().subtract('days', 1).toDate()
|
||||
user.set 'priv.lastCron', yesterday
|
||||
user.set 'lastCron', yesterday
|
||||
window.location.reload()
|
||||
|
||||
|
||||
@@ -6,13 +6,13 @@ derby = require 'derby'
|
||||
|
||||
userSchema =
|
||||
# _id
|
||||
pub:
|
||||
stats: { gp: 0, exp: 0, lvl: 1, hp: 50 }
|
||||
party: null
|
||||
invitations: []
|
||||
party: {
|
||||
current: null
|
||||
invitation: null
|
||||
}
|
||||
items: { armor: 0, weapon: 0 }
|
||||
preferences: { gender: 'm', armorSet: 'v1' }
|
||||
priv:
|
||||
idLists:
|
||||
habit: []
|
||||
daily: []
|
||||
@@ -31,37 +31,37 @@ userSchema =
|
||||
module.exports.newUserObject = ->
|
||||
# deep clone, else further new users get duplicate objects
|
||||
newUser = lodash.cloneDeep userSchema
|
||||
newUser.priv.apiToken = derby.uuid()
|
||||
newUser.apiToken = derby.uuid()
|
||||
for task in content.defaultTasks
|
||||
guid = task.id = derby.uuid()
|
||||
newUser.priv.tasks[guid] = task
|
||||
newUser.tasks[guid] = task
|
||||
switch task.type
|
||||
when 'habit' then newUser.priv.idLists.habit.push guid
|
||||
when 'daily' then newUser.priv.idLists.daily.push guid
|
||||
when 'todo' then newUser.priv.idLists.todo.push guid
|
||||
when 'reward' then newUser.priv.idLists.reward.push guid
|
||||
when 'habit' then newUser.idLists.habit.push guid
|
||||
when 'daily' then newUser.idLists.daily.push guid
|
||||
when 'todo' then newUser.idLists.todo.push guid
|
||||
when 'reward' then newUser.idLists.reward.push guid
|
||||
return newUser
|
||||
|
||||
module.exports.updateUser = (batch) ->
|
||||
user = batch.user
|
||||
obj = batch.obj()
|
||||
|
||||
batch.set('priv.apiToken', derby.uuid()) unless obj.priv.apiToken
|
||||
batch.set('apiToken', derby.uuid()) unless obj.apiToken
|
||||
|
||||
## Task List Cleanup
|
||||
# FIXME temporary hack to fix lists (Need to figure out why these are happening)
|
||||
tasks = obj.priv.tasks
|
||||
tasks = obj.tasks
|
||||
_.each ['habit','daily','todo','reward'], (type) ->
|
||||
# 1. remove duplicates
|
||||
# 2. restore missing zombie tasks back into list
|
||||
taskIds = _.pluck( _.where(tasks, {type:type}), 'id')
|
||||
union = _.union obj.priv.idLists[type], taskIds
|
||||
union = _.union obj.idLists[type], taskIds
|
||||
|
||||
# 2. remove empty (grey) tasks
|
||||
preened = _.filter(union, (val) -> _.contains(taskIds, val))
|
||||
|
||||
# There were indeed issues found, set the new list
|
||||
batch.set("priv.idLists.#{type}", preened) # if _.difference(preened, userObj[path]).length != 0
|
||||
batch.set("idLists.#{type}", preened) # if _.difference(preened, userObj[path]).length != 0
|
||||
|
||||
module.exports.BatchUpdate = BatchUpdate = (model) ->
|
||||
user = model.at("_user")
|
||||
@@ -100,9 +100,9 @@ module.exports.BatchUpdate = BatchUpdate = (model) ->
|
||||
eg, user.set('stats', {hp:50, exp:10...}) will break dom bindings, but user.set('stats.hp',50) is ok
|
||||
###
|
||||
setStats: (stats) ->
|
||||
stats ?= obj.pub.stats
|
||||
stats ?= obj.stats
|
||||
that = @
|
||||
_.each Object.keys(stats), (key) -> that.set "pub.stats.#{key}", stats[key]
|
||||
_.each Object.keys(stats), (key) -> that.set "stats.#{key}", stats[key]
|
||||
|
||||
# queue: (path, val) ->
|
||||
# # Special function for setting object properties by string dot-notation. See http://stackoverflow.com/a/6394168/362790
|
||||
|
||||
@@ -20,8 +20,8 @@ setModel = (m) ->
|
||||
{modifiers} may manually pass in stats as {weapon, exp}. This is used for testing
|
||||
###
|
||||
expModifier = (value, modifiers = {}) ->
|
||||
weapon = modifiers.weapon || user.get('pub.items.weapon')
|
||||
lvl = modifiers.lvl || user.get('pub.stats.lvl')
|
||||
weapon = modifiers.weapon || user.get('items.weapon')
|
||||
lvl = modifiers.lvl || user.get('stats.lvl')
|
||||
dmg = weapon * MODIFIER # each new weapon increases exp gain
|
||||
dmg += (lvl-1) * MODIFIER # same for lvls
|
||||
modified = value + (value * dmg)
|
||||
@@ -33,8 +33,8 @@ expModifier = (value, modifiers = {}) ->
|
||||
{modifiers} may manually pass in modifier as {armor, lvl}. This is used for testing
|
||||
###
|
||||
hpModifier = (value, modifiers = {}) ->
|
||||
armor = modifiers.armor || user.get('pub.items.armor')
|
||||
lvl = modifiers.lvl || user.get('pub.stats.lvl')
|
||||
armor = modifiers.armor || user.get('items.armor')
|
||||
lvl = modifiers.lvl || user.get('stats.lvl')
|
||||
ac = armor * MODIFIER # each new armor decreases HP loss
|
||||
ac += (lvl-1) * MODIFIER # same for lvls
|
||||
modified = value - (value * ac)
|
||||
@@ -62,37 +62,37 @@ updateStats = (newStats, batch) ->
|
||||
obj = batch.obj()
|
||||
|
||||
# if user is dead, dont do anything
|
||||
return if obj.pub.stats.lvl == 0
|
||||
return if obj.stats.lvl == 0
|
||||
|
||||
if newStats.hp?
|
||||
# Game Over
|
||||
if newStats.hp <= 0
|
||||
obj.pub.stats.lvl = 0 # signifies dead
|
||||
obj.pub.stats.hp = 0
|
||||
obj.stats.lvl = 0 # signifies dead
|
||||
obj.stats.hp = 0
|
||||
return
|
||||
else
|
||||
obj.pub.stats.hp = newStats.hp
|
||||
obj.stats.hp = newStats.hp
|
||||
|
||||
if newStats.exp?
|
||||
# level up & carry-over exp
|
||||
tnl = model.get '_tnl'
|
||||
if newStats.exp >= tnl
|
||||
newStats.exp -= tnl
|
||||
obj.pub.stats.lvl++
|
||||
obj.pub.stats.hp = 50
|
||||
if !obj.priv.flags.itemsEnabled and obj.pub.stats.lvl >= 2
|
||||
obj.stats.lvl++
|
||||
obj.stats.hp = 50
|
||||
if !obj.flags.itemsEnabled and obj.stats.lvl >= 2
|
||||
# Set to object, then also send to browser right away to get model.on() subscription notification
|
||||
batch.set 'priv.flags.itemsEnabled', true
|
||||
obj.priv.flags.itemsEnabled = true
|
||||
if !obj.priv.flags.partyEnabled and obj.pub.stats.lvl >= 3
|
||||
batch.set 'priv.flags.partyEnabled', true
|
||||
obj.priv.flags.partyEnabled = true
|
||||
obj.pub.stats.exp = newStats.exp
|
||||
batch.set 'flags.itemsEnabled', true
|
||||
obj.flags.itemsEnabled = true
|
||||
if !obj.flags.partyEnabled and obj.stats.lvl >= 3
|
||||
batch.set 'flags.partyEnabled', true
|
||||
obj.flags.partyEnabled = true
|
||||
obj.stats.exp = newStats.exp
|
||||
|
||||
if newStats.gp?
|
||||
#FIXME what was I doing here? I can't remember, gp isn't defined
|
||||
gp = 0.0 if (!gp? or gp<0)
|
||||
obj.pub.stats.gp = newStats.gp
|
||||
obj.stats.gp = newStats.gp
|
||||
|
||||
# {taskId} task you want to score
|
||||
# {direction} 'up' or 'down'
|
||||
@@ -106,10 +106,10 @@ score = (taskId, direction, times, batch, cron) ->
|
||||
batch.startTransaction()
|
||||
obj = batch.obj()
|
||||
|
||||
{gp, hp, exp, lvl} = obj.pub.stats
|
||||
{gp, hp, exp, lvl} = obj.stats
|
||||
|
||||
taskPath = "priv.tasks.#{taskId}"
|
||||
taskObj = obj.priv.tasks[taskId]
|
||||
taskPath = "tasks.#{taskId}"
|
||||
taskObj = obj.tasks[taskId]
|
||||
{type, value} = taskObj
|
||||
|
||||
delta = 0
|
||||
@@ -171,12 +171,12 @@ score = (taskId, direction, times, batch, cron) ->
|
||||
|
||||
taskObj.value = value
|
||||
batch.set "#{taskPath}.value", taskObj.value
|
||||
origStats = _.clone obj.pub.stats
|
||||
origStats = _.clone obj.stats
|
||||
updateStats {hp: hp, exp: exp, gp: gp}, batch
|
||||
if commit
|
||||
# newStats / origStats is a glorious hack to trick Derby into seeing the change in model.on(*)
|
||||
newStats = _.clone batch.obj().pub.stats
|
||||
_.each Object.keys(origStats), (key) -> obj.pub.stats[key] = origStats[key]
|
||||
newStats = _.clone batch.obj().stats
|
||||
_.each Object.keys(origStats), (key) -> obj.stats[key] = origStats[key]
|
||||
batch.setStats(newStats)
|
||||
# batch.setStats()
|
||||
batch.commit()
|
||||
@@ -192,12 +192,12 @@ cron = (resetDom_cb) ->
|
||||
if daysPassed > 0
|
||||
batch = new schema.BatchUpdate(model)
|
||||
batch.startTransaction()
|
||||
batch.set 'priv.lastCron', today
|
||||
batch.set 'lastCron', today
|
||||
obj = batch.obj()
|
||||
hpBefore = obj.pub.stats.hp #we'll use this later so we can animate hp loss
|
||||
hpBefore = obj.stats.hp #we'll use this later so we can animate hp loss
|
||||
# Tally each task
|
||||
todoTally = 0
|
||||
_.each obj.priv.tasks, (taskObj) ->
|
||||
_.each obj.tasks, (taskObj) ->
|
||||
unless taskObj.id?
|
||||
console.error "a task had a null id during cron, this should not be happening"
|
||||
return
|
||||
@@ -222,31 +222,31 @@ cron = (resetDom_cb) ->
|
||||
if type == 'daily'
|
||||
taskObj.history ?= []
|
||||
taskObj.history.push { date: +new Date, value: value }
|
||||
batch.set "priv.tasks.#{taskObj.id}.history", taskObj.history
|
||||
batch.set "priv.tasks.#{taskObj.id}.completed", false
|
||||
batch.set "tasks.#{taskObj.id}.history", taskObj.history
|
||||
batch.set "tasks.#{taskObj.id}.completed", false
|
||||
else
|
||||
value = obj.priv.tasks[taskObj.id].value #get updated value
|
||||
value = obj.tasks[taskObj.id].value #get updated value
|
||||
absVal = if (completed) then Math.abs(value) else value
|
||||
todoTally += absVal
|
||||
|
||||
# Finished tallying
|
||||
obj.priv.history ?= {}; obj.priv.history.todos ?= []; obj.priv.history.exp ?= []
|
||||
obj.priv.history.todos.push { date: today, value: todoTally }
|
||||
obj.history ?= {}; obj.history.todos ?= []; obj.history.exp ?= []
|
||||
obj.history.todos.push { date: today, value: todoTally }
|
||||
# tally experience
|
||||
expTally = obj.pub.stats.exp
|
||||
expTally = obj.stats.exp
|
||||
lvl = 0 #iterator
|
||||
while lvl < (obj.pub.stats.lvl-1)
|
||||
while lvl < (obj.stats.lvl-1)
|
||||
lvl++
|
||||
expTally += (lvl*100)/5
|
||||
obj.priv.history.exp.push { date: today, value: expTally }
|
||||
obj.history.exp.push { date: today, value: expTally }
|
||||
|
||||
# Set the new user specs, and animate HP loss
|
||||
[hpAfter, obj.pub.stats.hp] = [obj.pub.stats.hp, hpBefore]
|
||||
[hpAfter, obj.stats.hp] = [obj.stats.hp, hpBefore]
|
||||
batch.setStats()
|
||||
batch.set('history', obj.priv.history)
|
||||
batch.set('history', obj.history)
|
||||
batch.commit()
|
||||
resetDom_cb(model)
|
||||
setTimeout (-> user.set 'pub.stats.hp', hpAfter), 1000 # animate hp loss
|
||||
setTimeout (-> user.set 'stats.hp', hpAfter), 1000 # animate hp loss
|
||||
|
||||
|
||||
module.exports = {
|
||||
|
||||
@@ -31,8 +31,8 @@ module.exports.deleteStaleAccounts = ->
|
||||
collection.findEach un_registered, (err, user) ->
|
||||
throw err if err
|
||||
return unless user? #why does this happen sometimes?
|
||||
if !!user.priv.lastCron # for now ignore missing crons, still looking into why this is happening
|
||||
lastCron = new Date(user.priv.lastCron)
|
||||
if !!user.lastCron # for now ignore missing crons, still looking into why this is happening
|
||||
lastCron = new Date(user.lastCron)
|
||||
diff = Math.abs(moment(today).sod().diff(moment(lastCron).sod(), "days"))
|
||||
if diff > 10
|
||||
removeAccount(collection, user._id)
|
||||
|
||||
@@ -35,8 +35,8 @@ module.exports.app = (appExports, model) ->
|
||||
appExports.buyReroll = (e, el, next) ->
|
||||
batch = new schema.BatchUpdate(model)
|
||||
obj = model.get('_user')
|
||||
batch.set 'priv.balance', obj.priv.balance-1
|
||||
_.each obj.priv.tasks, (task) -> batch.set("priv.tasks.#{task.id}.value", 0) unless task.type == 'reward'
|
||||
batch.set 'balance', obj.balance-1
|
||||
_.each obj.tasks, (task) -> batch.set("tasks.#{task.id}.value", 0) unless task.type == 'reward'
|
||||
batch.commit()
|
||||
|
||||
module.exports.routes = (expressApp) ->
|
||||
@@ -53,8 +53,8 @@ module.exports.routes = (expressApp) ->
|
||||
userId = model.session.userId
|
||||
model.fetch "users.#{userId}", (err, user) ->
|
||||
model.ref '_user', "users.#{userId}"
|
||||
model.set('_user.priv.balance', model.get('_user.priv.balance')+5)
|
||||
model.set('_user.priv.flags.ads','hide')
|
||||
model.set('_user.balance', model.get('_user.balance')+5)
|
||||
model.set('_user.flags.ads','hide')
|
||||
return res.send(200)
|
||||
|
||||
api_key = process.env.STRIPE_API_KEY # secret stripe API key
|
||||
|
||||
@@ -49,8 +49,8 @@ module.exports = (expressApp, root, derby) ->
|
||||
|
||||
# Create task if doesn't exist
|
||||
# TODO add service & icon to task
|
||||
unless model.get("_user.priv.tasks.#{taskId}")
|
||||
model.refList "_habitList", "_user.priv.tasks", "_user.priv.idLists.habit"
|
||||
unless model.get("_user.tasks.#{taskId}")
|
||||
model.refList "_habitList", "_user.tasks", "_user.idLists.habit"
|
||||
model.at('_habitList').push {
|
||||
id: taskId
|
||||
type: 'habit'
|
||||
|
||||
@@ -14,28 +14,28 @@
|
||||
<pre class=prettyprint>{_user.id}</pre>
|
||||
|
||||
<h6>API Token</h6>
|
||||
<pre class=prettyprint>{_user.priv.apiToken}</pre>
|
||||
<pre class=prettyprint>{_user.apiToken}</pre>
|
||||
|
||||
<hr/>
|
||||
<h4>Gender</h4>
|
||||
<label class="radio">
|
||||
<input type="radio" name="genderRadios" value="m" x-bind="click:setMale" checked="{equal(_user.pub.preferences.gender,'m')}">
|
||||
<input type="radio" name="genderRadios" value="m" x-bind="click:setMale" checked="{equal(_user.preferences.gender,'m')}">
|
||||
Male
|
||||
</label>
|
||||
<label class="radio">
|
||||
<input type="radio" name="genderRadios" value="f" x-bind="click:setFemale" checked="{equal(_user.pub.preferences.gender,'f')}">
|
||||
<input type="radio" name="genderRadios" value="f" x-bind="click:setFemale" checked="{equal(_user.preferences.gender,'f')}">
|
||||
Female
|
||||
</label>
|
||||
|
||||
|
||||
{#if equal(_user.pub.preferences.gender,'f')}
|
||||
{#if equal(_user.preferences.gender,'f')}
|
||||
<h4>Armor Set</h4>
|
||||
<label class="radio">
|
||||
<input type="radio" name="armorSet" value="v1" x-bind="click:setArmorsetV1" checked="{equal(_user.pub.preferences.armorSet,'v1')}">
|
||||
<input type="radio" name="armorSet" value="v1" x-bind="click:setArmorsetV1" checked="{equal(_user.preferences.armorSet,'v1')}">
|
||||
v1
|
||||
</label>
|
||||
<label class="radio">
|
||||
<input type="radio" name="armorSet" value="v2" x-bind="click:setArmorsetV2" checked="{equal(_user.pub.preferences.armorSet,'v2')}">
|
||||
<input type="radio" name="armorSet" value="v2" x-bind="click:setArmorsetV2" checked="{equal(_user.preferences.armorSet,'v2')}">
|
||||
v2
|
||||
</label>
|
||||
{/}
|
||||
@@ -79,7 +79,7 @@
|
||||
</app:myModal>
|
||||
{/}
|
||||
<!-- Game Over Modal -->
|
||||
<div style="{#unless equal(_user.pub.stats.lvl,0)}display:none;{/}">
|
||||
<div style="{#unless equal(_user.stats.lvl,0)}display:none;{/}">
|
||||
<app:myModal noDismiss=true modalId='dead-modal'>
|
||||
<table>
|
||||
<tr>
|
||||
@@ -100,7 +100,7 @@
|
||||
<app:userTokens/>
|
||||
<p>Highly discouraged because red tasks provide good incentive to improve (<a target="_blank" href="https://github.com/lefnire/habitrpg#all-my-tasks-are-red-im-dying-too-fast">read more</a>). However, this becomes necessary after long bouts of bad habits.</p>
|
||||
<@footer>
|
||||
{#if lessThan(_user.priv.balance,1)}
|
||||
{#if lessThan(_user.balance,1)}
|
||||
<a data-dismiss="modal" x-bind="click:showStripe" class="btn btn-danger btn-large">Buy More Tokens</a><span class='token-cost'>Not enough tokens</span>
|
||||
{else}
|
||||
<a data-dismiss="modal" x-bind=click:buyReroll class="btn btn-danger btn-large">Re-Roll</a><span class='token-cost'>4 Tokens</span>
|
||||
@@ -125,7 +125,7 @@
|
||||
</ul>
|
||||
{/}
|
||||
|
||||
{#if equal(_user.priv.flags.kickstarter,'show')}
|
||||
{#if equal(_user.flags.kickstarter,'show')}
|
||||
<div class='alert alert-success'>
|
||||
<a x-bind="click:closeKickstarterNofitication" class='pull-right'>Dismiss</a>
|
||||
Help Habit by backing the <strong><a href="http://kck.st/XoA3Yg">Kickstarter</a></strong>! Funds iPhone & Android apps, <a href="https://github.com/lefnire/habitrpg/issues?labels=critical&page=1&state=open">bug fixes</a>, and the <a href="https://github.com/lefnire/habitrpg/issues/58">Groups feature</a>.
|
||||
@@ -165,39 +165,39 @@
|
||||
<!-- Avatar -->
|
||||
<td class="avatar main-avatar">
|
||||
<div class='avatar-sprites'>
|
||||
<img class='weapon weapon-{_user.pub.items.weapon}' src="/img/BrowserQuest/habitrpg_mods/weapon{_user.pub.items.weapon}.png" />
|
||||
<img class='armor armor-{_user.pub.items.armor}' src="/img/BrowserQuest/habitrpg_mods/{currentArmor(_user)}" />
|
||||
<img class='weapon weapon-{_user.items.weapon}' src="/img/BrowserQuest/habitrpg_mods/weapon{_user.items.weapon}.png" />
|
||||
<img class='armor armor-{_user.items.armor}' src="/img/BrowserQuest/habitrpg_mods/{currentArmor(_user)}" />
|
||||
</div>
|
||||
<div id="lvl"><span class="badge badge-info">Lvl {_user.pub.stats.lvl}</span></div>
|
||||
<div id="lvl"><span class="badge badge-info">Lvl {_user.stats.lvl}</span></div>
|
||||
</td>
|
||||
|
||||
<!-- Progress Bars -->
|
||||
<td id="bars" style="width:{#if _party}70%{else}90%{/};">
|
||||
<div class="progress progress-danger" rel=tooltip data-placement=bottom title="Health">
|
||||
<div class="bar" style="width: {percent(_user.pub.stats.hp, 50)}%;"></div>
|
||||
<span class="progress-text"><i class=icon-heart></i> {round(_user.pub.stats.hp)} / 50</span>
|
||||
<div class="bar" style="width: {percent(_user.stats.hp, 50)}%;"></div>
|
||||
<span class="progress-text"><i class=icon-heart></i> {round(_user.stats.hp)} / 50</span>
|
||||
</div>
|
||||
|
||||
<div class="progress progress-warning" rel=tooltip data-placement=bottom title="Experience">
|
||||
<div class="bar" style="width: {percent(_user.pub.stats.exp,_tnl)}%;"></div>
|
||||
<div class="bar" style="width: {percent(_user.stats.exp,_tnl)}%;"></div>
|
||||
<span class="progress-text">
|
||||
{#if _user.history.exp}
|
||||
<a x-bind=click:toggleChart data-toggle-id="exp-chart" data-history-path="_user.history.exp" rel=tooltip title="Progress"><i class=icon-signal></i></a>
|
||||
{/}
|
||||
<i class=icon-star></i> {round(_user.pub.stats.exp)} / {_tnl}
|
||||
<i class=icon-star></i> {round(_user.stats.exp)} / {_tnl}
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<!-- Party -->
|
||||
{#if _user.priv.flags.partyEnabled}
|
||||
{#if _user.flags.partyEnabled}
|
||||
{#each _party as :member}
|
||||
<td class="avatar party-avatar" rel="tooltip" title="{username(:member.auth)}" data-placement="bottom" >
|
||||
<div class='avatar-sprites'>
|
||||
<img class='weapon weapon-{:member.pub.items.weapon}' src="/img/BrowserQuest/habitrpg_mods/weapon{:member.pub.items.weapon}.png" />
|
||||
<img class='armor armor-{:member.pub.items.armor}' src="/img/BrowserQuest/habitrpg_mods/{currentArmor(:member)}" />
|
||||
<img class='weapon weapon-{:member.items.weapon}' src="/img/BrowserQuest/habitrpg_mods/weapon{:member.items.weapon}.png" />
|
||||
<img class='armor armor-{:member.items.armor}' src="/img/BrowserQuest/habitrpg_mods/{currentArmor(:member)}" />
|
||||
</div>
|
||||
<div id="lvl"><span class="badge badge-info">Lvl {:member.pub.stats.lvl}</span></div>
|
||||
<div id="lvl"><span class="badge badge-info">Lvl {:member.stats.lvl}</span></div>
|
||||
</td>
|
||||
{/}
|
||||
<td><a class="btn" id="add-party-button" data-target="#add-party-modal" data-toggle="modal"><i class="icon-user"></i></a></td>
|
||||
@@ -281,7 +281,7 @@
|
||||
<!--Title -->
|
||||
<div class="row-fluid">
|
||||
<div class="span6"><h2>Rewards</h2></div>
|
||||
<div class="span6" id="money">{gold(_user.pub.stats.money)} <img src='/img/coin_single_gold.png'/> {silver(_user.pub.stats.money)} <img src='/img/coin_single_silver.png'/></div>
|
||||
<div class="span6" id="money">{gold(_user.stats.money)} <img src='/img/coin_single_gold.png'/> {silver(_user.stats.money)} <img src='/img/coin_single_silver.png'/></div>
|
||||
</div>
|
||||
|
||||
<!-- Content -->
|
||||
@@ -289,7 +289,7 @@
|
||||
{#each _rewardList as :task}<app:task />{/}
|
||||
</ul>
|
||||
|
||||
{#if _user.priv.flags.itemsEnabled}
|
||||
{#if _user.flags.itemsEnabled}
|
||||
<ul class='items'>
|
||||
{#with _view.items.armor as :item}<app:item />{/}
|
||||
{#with _view.items.weapon as :item}<app:item />{/}
|
||||
@@ -346,12 +346,12 @@
|
||||
<userTokens:>
|
||||
<div class="pull-right">
|
||||
<div class="input-append">
|
||||
<span class="uneditable-input" style="width:auto;">{tokens(_user.priv.balance)}</span>
|
||||
<span class="uneditable-input" style="width:auto;">{tokens(_user.balance)}</span>
|
||||
<span class="add-on">Tokens</span>
|
||||
</div>
|
||||
<a class="label" data-toggle="modal" href='#reset-modal'><i class="icon-ban-circle"></i>Reset</a>
|
||||
</div>
|
||||
<!--<span class="well pull-right">Tokens: {tokens(_user.priv.balance)}</span>-->
|
||||
<!--<span class="well pull-right">Tokens: {tokens(_user.balance)}</span>-->
|
||||
|
||||
<newTask: nonvoid>
|
||||
<form class="form-inline new-task-form" id=new-{{@type}} data-task-type={{@type}} x-bind=submit:addTask>
|
||||
|
||||
Reference in New Issue
Block a user