mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-27 09:35:39 -05:00
Added achievement preview, exp test, stuff
This commit is contained in:
parent
45798aab02
commit
39fb2cb1b4
12 changed files with 104 additions and 18 deletions
|
@ -7,6 +7,9 @@ module.exports = class User extends CocoModel
|
||||||
@schema: require 'schemas/models/user'
|
@schema: require 'schemas/models/user'
|
||||||
urlRoot: "/db/user"
|
urlRoot: "/db/user"
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
points: 0
|
||||||
|
|
||||||
initialize: ->
|
initialize: ->
|
||||||
super()
|
super()
|
||||||
@migrateEmails()
|
@migrateEmails()
|
||||||
|
@ -88,7 +91,3 @@ module.exports = class User extends CocoModel
|
||||||
|
|
||||||
level: ->
|
level: ->
|
||||||
User.levelFromExp(@get('points'))
|
User.levelFromExp(@get('points'))
|
||||||
|
|
||||||
levelFromExp: (xp) -> User.levelFromExp(xp)
|
|
||||||
|
|
||||||
expForLevel: (level) -> User.expForLevel(level)
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
#editor-achievement-edit-view
|
#editor-achievement-edit-view
|
||||||
|
height: 100%
|
||||||
|
|
||||||
.treema-root
|
.treema-root
|
||||||
margin: 28px 0px 20px
|
margin: 28px 0px 20px
|
||||||
|
|
||||||
|
@ -10,3 +12,9 @@
|
||||||
textarea
|
textarea
|
||||||
width: 92%
|
width: 92%
|
||||||
height: 300px
|
height: 300px
|
||||||
|
|
||||||
|
#achievement-view
|
||||||
|
min-height: 200px
|
||||||
|
|
||||||
|
.notifyjs-container
|
||||||
|
clear: both
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
position: absolute
|
position: absolute
|
||||||
width: 200px
|
width: 200px
|
||||||
height: 200px
|
height: 200px
|
||||||
left: -150px
|
left: -140px
|
||||||
top: 0px
|
top: 0px
|
||||||
|
|
||||||
.achievement-image
|
.achievement-image
|
||||||
|
@ -66,18 +66,30 @@
|
||||||
&:empty
|
&:empty
|
||||||
display: none
|
display: none
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.progress-wrapper
|
.progress-wrapper
|
||||||
position: absolute
|
position: absolute
|
||||||
padding-right: 30px
|
padding-right: 30px
|
||||||
bottom: 0px
|
bottom: 0px
|
||||||
|
|
||||||
|
.achievement-level
|
||||||
|
float: left
|
||||||
|
font-size: 15px
|
||||||
|
|
||||||
.progress-bar-wrapper
|
.progress-bar-wrapper
|
||||||
|
padding-left: 30px
|
||||||
width: 100%
|
width: 100%
|
||||||
.progress
|
.progress
|
||||||
border-radius: 20px
|
border-radius: 20px
|
||||||
|
|
||||||
.progress-bar-border
|
.progress-bar-border
|
||||||
|
padding-left: 30px
|
||||||
position: relative
|
position: relative
|
||||||
top: -44px
|
top: -44px
|
||||||
|
|
||||||
|
.progress-bar-border img
|
||||||
|
width: 100%
|
||||||
/*.earned-exp
|
/*.earned-exp
|
||||||
padding-left: 5px
|
padding-left: 5px
|
||||||
font-family: Bangers
|
font-family: Bangers
|
||||||
|
|
|
@ -10,6 +10,7 @@ div
|
||||||
.achievement-message(data-notify-html="message")
|
.achievement-message(data-notify-html="message")
|
||||||
.progress-wrapper
|
.progress-wrapper
|
||||||
//.earned-exp(data-notify-html="earnedExp")
|
//.earned-exp(data-notify-html="earnedExp")
|
||||||
|
span.achievement-level.badge(data-notify-html="level")
|
||||||
.progress-bar-wrapper(data-notify-html="progressBar")
|
.progress-bar-wrapper(data-notify-html="progressBar")
|
||||||
.progress-bar-border
|
.progress-bar-border(data-notify-html="barBorder")
|
||||||
img(src='/images/achievements/bar_border.png' width='100%')
|
//img(src='/images/achievements/bar_border.png' width='100%')
|
||||||
|
|
|
@ -21,10 +21,11 @@ block content
|
||||||
#achievement-treema
|
#achievement-treema
|
||||||
|
|
||||||
#achievement-view
|
#achievement-view
|
||||||
|
#achievement-view-inner
|
||||||
|
|
||||||
hr
|
hr
|
||||||
|
|
||||||
div#error-view
|
#error-view
|
||||||
|
|
||||||
else
|
else
|
||||||
.alert.alert-danger
|
.alert.alert-danger
|
||||||
|
|
|
@ -49,15 +49,38 @@ module.exports = class AchievementEditView extends View
|
||||||
|
|
||||||
@treema.build()
|
@treema.build()
|
||||||
|
|
||||||
pushChangesToPreview: =>
|
|
||||||
'TODO' # TODO might want some intrinsic preview thing
|
|
||||||
|
|
||||||
getRenderData: (context={}) ->
|
getRenderData: (context={}) ->
|
||||||
context = super(context)
|
context = super(context)
|
||||||
context.achievement = @achievement
|
context.achievement = @achievement
|
||||||
context.authorized = me.isAdmin()
|
context.authorized = me.isAdmin()
|
||||||
context
|
context
|
||||||
|
|
||||||
|
afterRender: ->
|
||||||
|
super(arguments...)
|
||||||
|
@pushChangesToPreview()
|
||||||
|
|
||||||
|
pushChangesToPreview: =>
|
||||||
|
$('.notifyjs-wrapper').trigger 'notify-hide'
|
||||||
|
|
||||||
|
if @treema?
|
||||||
|
for key, value of @treema.data
|
||||||
|
@achievement.set key, value
|
||||||
|
|
||||||
|
earned =
|
||||||
|
earnedPoints: @achievement.get 'worth'
|
||||||
|
|
||||||
|
data = @createNotifyData @achievement, earned
|
||||||
|
options =
|
||||||
|
style: 'achievement'
|
||||||
|
autoHide: false
|
||||||
|
clickToHide: false
|
||||||
|
arrowShow: false
|
||||||
|
elementPosition: 'bottom center'
|
||||||
|
hideDuration: 0
|
||||||
|
showDuration: 0
|
||||||
|
l
|
||||||
|
$('#achievement-view-inner').notify data, options
|
||||||
|
|
||||||
openSaveModal: ->
|
openSaveModal: ->
|
||||||
'Maybe later' # TODO
|
'Maybe later' # TODO
|
||||||
|
|
||||||
|
|
|
@ -51,12 +51,32 @@ module.exports = class RootView extends CocoView
|
||||||
newlyAchievedBar = $("<div data-toggle='tooltip' class='progress-bar progress-bar-success' style='width:#{newlyAchievedPercentage}%'></div>")
|
newlyAchievedBar = $("<div data-toggle='tooltip' class='progress-bar progress-bar-success' style='width:#{newlyAchievedPercentage}%'></div>")
|
||||||
emptyBar = $("<div data-toggle='tooltip' class='progress-bar progress-bar-white' style='width:#{100 - newlyAchievedPercentage - alreadyAchievedPercentage}%'></div>")
|
emptyBar = $("<div data-toggle='tooltip' class='progress-bar progress-bar-white' style='width:#{100 - newlyAchievedPercentage - alreadyAchievedPercentage}%'></div>")
|
||||||
progressBar = $('<div class="progress" data-toggle="tooltip"></div>').append(alreadyAchievedBar).append(newlyAchievedBar).append(emptyBar)
|
progressBar = $('<div class="progress" data-toggle="tooltip"></div>').append(alreadyAchievedBar).append(newlyAchievedBar).append(emptyBar)
|
||||||
message = if (currentLevel isnt 1) and leveledUp then "Reached level #{currentLevel}!" else null
|
#message = if (currentLevel isnt 1) and leveledUp then "Reached level #{currentLevel}!" else null
|
||||||
|
|
||||||
alreadyAchievedBar.tooltip(title: "#{currentExp} XP in total")
|
alreadyAchievedBar.tooltip(title: "#{currentExp} XP in total")
|
||||||
newlyAchievedBar.tooltip(title: "#{achievedExp} XP earned")
|
newlyAchievedBar.tooltip(title: "#{achievedExp} XP earned")
|
||||||
emptyBar.tooltip(title: "#{nextLevelExp - currentExp} XP until level #{nextLevel}")
|
emptyBar.tooltip(title: "#{nextLevelExp - currentExp} XP until level #{nextLevel}")
|
||||||
|
|
||||||
|
barBorder = $('<img src="/images/achievements/bar_border.png" />')
|
||||||
|
|
||||||
|
barBorder.hover (e) ->
|
||||||
|
#console.debug e
|
||||||
|
x = e.pageX
|
||||||
|
y = e.pageY
|
||||||
|
$actualHover = _.find [$('.progress-bar-warning'), $('.progress-bar-success'), $('.progress-bar-white')], (el) ->
|
||||||
|
offset = el.offset()
|
||||||
|
l = offset.left
|
||||||
|
t = offset.top
|
||||||
|
h = el.height() + 10
|
||||||
|
w = el.width() + 10
|
||||||
|
|
||||||
|
maxx = l + w
|
||||||
|
maxy = t + h
|
||||||
|
|
||||||
|
return (y <= maxy && y >= t) && (x <= maxx && x >= l) ? true : null
|
||||||
|
#console.debug $actualHover
|
||||||
|
$actualHover.trigger e if $actualHover
|
||||||
|
|
||||||
# TODO a default should be linked here
|
# TODO a default should be linked here
|
||||||
imageURL = '/file/' + achievement.get('icon')
|
imageURL = '/file/' + achievement.get('icon')
|
||||||
data =
|
data =
|
||||||
|
@ -65,7 +85,10 @@ module.exports = class RootView extends CocoView
|
||||||
description: achievement.get('description')
|
description: achievement.get('description')
|
||||||
progressBar: progressBar
|
progressBar: progressBar
|
||||||
earnedExp: "+ #{achievedExp} XP"
|
earnedExp: "+ #{achievedExp} XP"
|
||||||
message: message
|
#message: message
|
||||||
|
level: currentLevel
|
||||||
|
barBorder: barBorder
|
||||||
|
|
||||||
data
|
data
|
||||||
|
|
||||||
showNewAchievement: (achievement, earnedAchievement) ->
|
showNewAchievement: (achievement, earnedAchievement) ->
|
||||||
|
|
|
@ -32,6 +32,8 @@ AchievementSchema.methods.getExpFunction = ->
|
||||||
AchievementSchema.statics.jsonschema = jsonschema
|
AchievementSchema.statics.jsonschema = jsonschema
|
||||||
AchievementSchema.statics.achievements = {}
|
AchievementSchema.statics.achievements = {}
|
||||||
|
|
||||||
|
# Reloads all achievements into memory.
|
||||||
|
# TODO might want to tweak this to only load new achievements
|
||||||
AchievementSchema.statics.loadAchievements = (done) ->
|
AchievementSchema.statics.loadAchievements = (done) ->
|
||||||
AchievementSchema.statics.resetAchievements()
|
AchievementSchema.statics.resetAchievements()
|
||||||
Achievement = require('../achievements/Achievement')
|
Achievement = require('../achievements/Achievement')
|
||||||
|
@ -49,6 +51,7 @@ AchievementSchema.statics.getLoadedAchievements = ->
|
||||||
AchievementSchema.statics.resetAchievements = ->
|
AchievementSchema.statics.resetAchievements = ->
|
||||||
delete AchievementSchema.statics.achievements[category] for category of AchievementSchema.statics.achievements
|
delete AchievementSchema.statics.achievements[category] for category of AchievementSchema.statics.achievements
|
||||||
|
|
||||||
|
# Queries are stored as JSON strings, objectify them upon loading
|
||||||
AchievementSchema.post 'init', (doc) -> doc.objectifyQuery()
|
AchievementSchema.post 'init', (doc) -> doc.objectifyQuery()
|
||||||
|
|
||||||
AchievementSchema.pre 'save', (next) ->
|
AchievementSchema.pre 'save', (next) ->
|
||||||
|
|
|
@ -25,7 +25,7 @@ AchievablePlugin = (schema, options) ->
|
||||||
if doc.isInit('_id') and not doc.id of before
|
if doc.isInit('_id') and not doc.id of before
|
||||||
log.warn 'document was already initialized but did not go through `init` and is therefore treated as new while it might not be'
|
log.warn 'document was already initialized but did not go through `init` and is therefore treated as new while it might not be'
|
||||||
|
|
||||||
category = doc.constructor.modelName
|
category = doc.constructor.collection.name
|
||||||
loadedAchievements = Achievement.getLoadedAchievements()
|
loadedAchievements = Achievement.getLoadedAchievements()
|
||||||
#log.debug 'about to save ' + category + ', number of achievements is ' + Object.keys(loadedAchievements).length
|
#log.debug 'about to save ' + category + ', number of achievements is ' + Object.keys(loadedAchievements).length
|
||||||
|
|
||||||
|
|
16
test/app/models/User.spec.coffee
Normal file
16
test/app/models/User.spec.coffee
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
User = require 'models/User'
|
||||||
|
|
||||||
|
describe 'UserModel', ->
|
||||||
|
it 'experience functions are correct', ->
|
||||||
|
expect(User.expForLevel(User.levelFromExp 0)).toBe 0
|
||||||
|
expect(User.expForLevel(User.levelFromExp 50)).toBe 50
|
||||||
|
expect(User.expForLevel 1).toBe 0
|
||||||
|
expect(User.expForLevel 2).toBeGreaterThan User.expForLevel 1
|
||||||
|
|
||||||
|
it 'level is calculated correctly', ->
|
||||||
|
me.set 'points', 0
|
||||||
|
expect(me.level()).toBe 1
|
||||||
|
|
||||||
|
me.set 'points', 50
|
||||||
|
expect(me.level()).toBe User.levelFromExp 50
|
||||||
|
|
|
@ -8,7 +8,7 @@ class MockServer
|
||||||
|
|
||||||
|
|
||||||
module.exports = ->
|
module.exports = ->
|
||||||
me.set('points', 48)
|
me.set 'points', 48
|
||||||
|
|
||||||
unlockableObj =
|
unlockableObj =
|
||||||
name: 'Dungeon Arena Started'
|
name: 'Dungeon Arena Started'
|
||||||
|
|
|
@ -4,7 +4,7 @@ unlockable =
|
||||||
name: 'Dungeon Arena Started'
|
name: 'Dungeon Arena Started'
|
||||||
description: 'Started playing Dungeon Arena.'
|
description: 'Started playing Dungeon Arena.'
|
||||||
worth: 3
|
worth: 3
|
||||||
collection: 'level.session'
|
collection: 'level.sessions'
|
||||||
query: "{\"level.original\":\"dungeon-arena\"}"
|
query: "{\"level.original\":\"dungeon-arena\"}"
|
||||||
userField: 'creator'
|
userField: 'creator'
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ repeatable =
|
||||||
name: 'Simulated'
|
name: 'Simulated'
|
||||||
description: 'Simulated Games.'
|
description: 'Simulated Games.'
|
||||||
worth: 1
|
worth: 1
|
||||||
collection: 'User'
|
collection: 'users'
|
||||||
query: "{\"simulatedBy\":{\"$gt\":\"0\"}}"
|
query: "{\"simulatedBy\":{\"$gt\":\"0\"}}"
|
||||||
userField: '_id'
|
userField: '_id'
|
||||||
proportionalTo: 'simulatedBy'
|
proportionalTo: 'simulatedBy'
|
||||||
|
@ -20,7 +20,7 @@ repeatable =
|
||||||
diminishing =
|
diminishing =
|
||||||
name: 'Simulated2'
|
name: 'Simulated2'
|
||||||
worth: 1.5
|
worth: 1.5
|
||||||
collection: 'User'
|
collection: 'users'
|
||||||
query: "{\"simulatedBy\":{\"$gt\":\"0\"}}"
|
query: "{\"simulatedBy\":{\"$gt\":\"0\"}}"
|
||||||
userField: '_id'
|
userField: '_id'
|
||||||
proportionalTo: 'simulatedBy'
|
proportionalTo: 'simulatedBy'
|
||||||
|
|
Loading…
Reference in a new issue