mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-05-03 17:33:31 -04:00
Merge branch 'master' into production
This commit is contained in:
commit
318b499e3e
11 changed files with 146 additions and 74 deletions
app
lib
styles/play/level/tome
templates/play/level/tome
views
editor/level/modals
play
server/achievements
|
@ -39,7 +39,12 @@ module.exports = class Angel extends CocoClass
|
||||||
|
|
||||||
# say: debugging stuff, usually off; log: important performance indicators, keep on
|
# say: debugging stuff, usually off; log: important performance indicators, keep on
|
||||||
say: (args...) -> #@log args...
|
say: (args...) -> #@log args...
|
||||||
log: (args...) -> console.info "|#{@shared.godNick}'s #{@nick}|", args...
|
log: ->
|
||||||
|
# console.info.apply is undefined in IE9, CofeeScript splats invocation won't work.
|
||||||
|
# http://stackoverflow.com/questions/5472938/does-ie9-support-console-log-and-is-it-a-real-function
|
||||||
|
message = "|#{@shared.godNick}'s #{@nick}|"
|
||||||
|
message += " #{arg}" for arg in arguments
|
||||||
|
console.info message
|
||||||
|
|
||||||
testWorker: =>
|
testWorker: =>
|
||||||
return if @destroyed
|
return if @destroyed
|
||||||
|
@ -238,7 +243,13 @@ module.exports = class Angel extends CocoClass
|
||||||
console?.profile? "World Generation #{(Math.random() * 1000).toFixed(0)}" if imitateIE9?
|
console?.profile? "World Generation #{(Math.random() * 1000).toFixed(0)}" if imitateIE9?
|
||||||
work.t0 = now()
|
work.t0 = now()
|
||||||
work.testWorld = testWorld = new World work.userCodeMap
|
work.testWorld = testWorld = new World work.userCodeMap
|
||||||
|
work.testWorld.levelSessionIDs = work.levelSessionIDs
|
||||||
|
work.testWorld.submissionCount = work.submissionCount
|
||||||
|
work.testWorld.flagHistory = work.flagHistory ? []
|
||||||
testWorld.loadFromLevel work.level
|
testWorld.loadFromLevel work.level
|
||||||
|
work.testWorld.preloading = work.preload
|
||||||
|
work.testWorld.headless = work.headless
|
||||||
|
work.testWorld.realTime = work.realTime
|
||||||
if @shared.goalManager
|
if @shared.goalManager
|
||||||
testGM = new GoalManager(testWorld)
|
testGM = new GoalManager(testWorld)
|
||||||
testGM.setGoals work.goals
|
testGM.setGoals work.goals
|
||||||
|
@ -254,7 +265,7 @@ module.exports = class Angel extends CocoClass
|
||||||
work.testWorld.goalManager.worldGenerationEnded() if work.testWorld.ended
|
work.testWorld.goalManager.worldGenerationEnded() if work.testWorld.ended
|
||||||
serialized = testWorld.serialize()
|
serialized = testWorld.serialize()
|
||||||
window.BOX2D_ENABLED = false
|
window.BOX2D_ENABLED = false
|
||||||
World.deserialize serialized.serializedWorld, @shared.worldClassMap, @shared.lastSerializedWorldFrames, @finishBeholdingWorld(goalStates), serialized.startFrame, work.level, serialized.endFrame
|
World.deserialize serialized.serializedWorld, @shared.worldClassMap, @shared.lastSerializedWorldFrames, @finishBeholdingWorld(goalStates), serialized.startFrame, serialized.endFrame, work.level
|
||||||
window.BOX2D_ENABLED = true
|
window.BOX2D_ENABLED = true
|
||||||
@shared.lastSerializedWorldFrames = serialized.serializedWorld.frames
|
@shared.lastSerializedWorldFrames = serialized.serializedWorld.frames
|
||||||
|
|
||||||
|
|
|
@ -51,3 +51,4 @@ functionParameters =
|
||||||
initializeCentroids: []
|
initializeCentroids: []
|
||||||
update: []
|
update: []
|
||||||
getNearestEnemy: []
|
getNearestEnemy: []
|
||||||
|
die: []
|
||||||
|
|
|
@ -49,11 +49,15 @@
|
||||||
body:not(.dialogue-view-active)
|
body:not(.dialogue-view-active)
|
||||||
.spell-palette-popover.popover
|
.spell-palette-popover.popover
|
||||||
right: 45%
|
right: 45%
|
||||||
min-width: 350px
|
min-width: 500px
|
||||||
|
|
||||||
.spell-palette-popover.popover
|
.spell-palette-popover.popover
|
||||||
// Only those popovers which are our direct children (spell documentation)
|
// Only those popovers which are our direct children (spell documentation)
|
||||||
max-width: 600px
|
max-width: 600px
|
||||||
|
padding: 0
|
||||||
|
border-image: url(/images/level/popover_background.png) 29 39 fill stretch
|
||||||
|
border-width: 15px 20px
|
||||||
|
@include box-shadow(0 0 0 #000)
|
||||||
|
|
||||||
// Jiggle animation
|
// Jiggle animation
|
||||||
// TODO: consolidate with problem_alert.sass jiggle
|
// TODO: consolidate with problem_alert.sass jiggle
|
||||||
|
@ -98,13 +102,8 @@ body:not(.dialogue-view-active)
|
||||||
&:hover
|
&:hover
|
||||||
@include opacity(1)
|
@include opacity(1)
|
||||||
|
|
||||||
padding: 0
|
|
||||||
border-image: url(/images/level/popover_background.png) 29 39 fill stretch
|
|
||||||
border-width: 15px 20px
|
|
||||||
@include box-shadow(0 0 0 #000)
|
|
||||||
|
|
||||||
h1:not(.not-code), h2:not(.not-code), h3:not(.not-code), h4:not(.not-code), h5:not(.not-code), h6:not(.not-code)
|
h1:not(.not-code), h2:not(.not-code), h3:not(.not-code), h4:not(.not-code), h5:not(.not-code), h6:not(.not-code)
|
||||||
font-family: Menlo, Monaco, Consolas, "Courier New", monospace
|
font-family: Monaco, Menlo, Ubuntu Mono, Consolas, "source-code-pro", monospace !important
|
||||||
font-variant: normal
|
font-variant: normal
|
||||||
|
|
||||||
.popover-title
|
.popover-title
|
||||||
|
@ -129,6 +128,24 @@ body:not(.dialogue-view-active)
|
||||||
&.right .arrow
|
&.right .arrow
|
||||||
left: -3%
|
left: -3%
|
||||||
|
|
||||||
|
.docs-ace-container
|
||||||
|
padding: 2px 4px
|
||||||
|
border-radius: 4px
|
||||||
|
|
||||||
|
&, .docs-ace
|
||||||
|
background-color: #f9f2f4
|
||||||
|
font-size: 12px
|
||||||
|
font-family: Monaco, Menlo, Ubuntu Mono, Consolas, "source-code-pro", monospace !important
|
||||||
|
|
||||||
|
.docs-ace
|
||||||
|
.ace_cursor, .ace_bracket
|
||||||
|
display: none
|
||||||
|
|
||||||
|
code
|
||||||
|
color: black
|
||||||
|
font-family: Monaco, Menlo, Ubuntu Mono, Consolas, "source-code-pro", monospace !important
|
||||||
|
font-size: 12px
|
||||||
|
|
||||||
html.no-borderimage
|
html.no-borderimage
|
||||||
.spell-palette-popover.popover
|
.spell-palette-popover.popover
|
||||||
background: transparent url(/images/level/popover_background.png)
|
background: transparent url(/images/level/popover_background.png)
|
||||||
|
|
|
@ -62,25 +62,28 @@ if !selectedMethod
|
||||||
strong
|
strong
|
||||||
span(data-i18n="skill_docs.example") Example
|
span(data-i18n="skill_docs.example") Example
|
||||||
| :
|
| :
|
||||||
div!= marked("```\n" + doc.example + "```")
|
.docs-ace-container
|
||||||
|
.docs-ace= doc.example
|
||||||
else if doc.type == 'function' && argumentExamples.length
|
else if doc.type == 'function' && argumentExamples.length
|
||||||
p.example
|
p.example
|
||||||
strong
|
strong
|
||||||
span(data-i18n="skill_docs.example") Example
|
span(data-i18n="skill_docs.example") Example
|
||||||
| :
|
| :
|
||||||
div
|
div
|
||||||
if language == 'javascript'
|
.docs-ace-container
|
||||||
code= doc.owner + '.' + doc.name + '(' + argumentExamples.join(', ') + ');'
|
.docs-ace
|
||||||
else if language == 'coffeescript'
|
if language == 'javascript'
|
||||||
code= doc.ownerName + (doc.ownerName == '@' ? '' : '.') + doc.name + ' ' + argumentExamples.join(', ')
|
span= doc.owner + '.' + doc.name + '(' + argumentExamples.join(', ') + ');'
|
||||||
else if language == 'python'
|
else if language == 'coffeescript'
|
||||||
code= doc.ownerName + '.' + doc.name + '(' + argumentExamples.join(', ') + ')'
|
span= doc.ownerName + (doc.ownerName == '@' ? '' : '.') + doc.name + ' ' + argumentExamples.join(', ')
|
||||||
else if language == 'clojure'
|
else if language == 'python'
|
||||||
code= '(.' + doc.name + ' ' + doc.ownerName + ' ' + argumentExamples.join(', ') + ')'
|
span= doc.ownerName + '.' + doc.name + '(' + argumentExamples.join(', ') + ')'
|
||||||
else if language == 'lua'
|
else if language == 'clojure'
|
||||||
code= doc.ownerName + ':' + doc.name + '(' + argumentExamples.join(', ') + ')'
|
span= '(.' + doc.name + ' ' + doc.ownerName + ' ' + argumentExamples.join(', ') + ')'
|
||||||
else if language == 'io'
|
else if language == 'lua'
|
||||||
code= (doc.ownerName == 'this' ? '' : doc.ownerName + ' ') + doc.name + '(' + argumentExamples.join(', ') + ')'
|
span= doc.ownerName + ':' + doc.name + '(' + argumentExamples.join(', ') + ')'
|
||||||
|
else if language == 'io'
|
||||||
|
span= (doc.ownerName == 'this' ? '' : doc.ownerName + ' ') + doc.name + '(' + argumentExamples.join(', ') + ')'
|
||||||
|
|
||||||
if (doc.type != 'function' && doc.type != 'snippet') || doc.name == 'now'
|
if (doc.type != 'function' && doc.type != 'snippet') || doc.name == 'now'
|
||||||
p.value
|
p.value
|
||||||
|
|
|
@ -15,6 +15,10 @@ clusters = {
|
||||||
'thangs': ['Tree 1', 'Tree 2', 'Tree 3', 'Tree 4']
|
'thangs': ['Tree 1', 'Tree 2', 'Tree 3', 'Tree 4']
|
||||||
'margin': 0.5
|
'margin': 0.5
|
||||||
}
|
}
|
||||||
|
'tree_stands': {
|
||||||
|
'thangs': ['Tree Stand 1', 'Tree Stand 2', 'Tree Stand 3', 'Tree Stand 4', 'Tree Stand 5', 'Tree Stand 6']
|
||||||
|
'margin': 3
|
||||||
|
}
|
||||||
'shrubs': {
|
'shrubs': {
|
||||||
'thangs': ['Shrub 1', 'Shrub 2', 'Shrub 3']
|
'thangs': ['Shrub 1', 'Shrub 2', 'Shrub 3']
|
||||||
'margin': 0.5
|
'margin': 0.5
|
||||||
|
@ -165,10 +169,10 @@ presets = {
|
||||||
'grassy': {
|
'grassy': {
|
||||||
'terrainName': 'Grass'
|
'terrainName': 'Grass'
|
||||||
'type':'grassy'
|
'type':'grassy'
|
||||||
'borders':'trees'
|
'borders':'tree_stands'
|
||||||
'borderNoise':1
|
'borderNoise':1
|
||||||
'borderSize':0
|
'borderSize':2
|
||||||
'borderThickness':3
|
'borderThickness':2
|
||||||
'floors':'grass_floor'
|
'floors':'grass_floor'
|
||||||
'decorations': {
|
'decorations': {
|
||||||
'hero': {
|
'hero': {
|
||||||
|
|
|
@ -728,7 +728,6 @@ forest = [
|
||||||
description: 'Join forces with a new hero: Amara Arrowhead.'
|
description: 'Join forces with a new hero: Amara Arrowhead.'
|
||||||
nextLevels:
|
nextLevels:
|
||||||
continue: 'swift-dagger'
|
continue: 'swift-dagger'
|
||||||
disabled: not me.isAdmin()
|
|
||||||
x: 64.37
|
x: 64.37
|
||||||
y: 69.18
|
y: 69.18
|
||||||
}
|
}
|
||||||
|
@ -740,7 +739,6 @@ forest = [
|
||||||
description: 'Deal damage from a distance with your new hero.'
|
description: 'Deal damage from a distance with your new hero.'
|
||||||
nextLevels:
|
nextLevels:
|
||||||
continue: 'shrapnel'
|
continue: 'shrapnel'
|
||||||
disabled: not me.isAdmin()
|
|
||||||
x: 66
|
x: 66
|
||||||
y: 75.61
|
y: 75.61
|
||||||
}
|
}
|
||||||
|
@ -752,7 +750,6 @@ forest = [
|
||||||
description: 'Explore the explosive arts.'
|
description: 'Explore the explosive arts.'
|
||||||
nextLevels:
|
nextLevels:
|
||||||
continue: 'coinucopia'
|
continue: 'coinucopia'
|
||||||
disabled: not me.isAdmin()
|
|
||||||
x: 67
|
x: 67
|
||||||
y: 81
|
y: 81
|
||||||
}
|
}
|
||||||
|
@ -766,7 +763,6 @@ forest = [
|
||||||
description: 'Stand your ground against large ogres with a new hero: Ms. Hushbaum.'
|
description: 'Stand your ground against large ogres with a new hero: Ms. Hushbaum.'
|
||||||
nextLevels:
|
nextLevels:
|
||||||
continue: 'touch-of-death'
|
continue: 'touch-of-death'
|
||||||
disabled: not me.isAdmin()
|
|
||||||
x: 64.37
|
x: 64.37
|
||||||
y: 55.18
|
y: 55.18
|
||||||
}
|
}
|
||||||
|
@ -778,7 +774,6 @@ forest = [
|
||||||
description: 'Learn your first spell to siphon life from your foes.'
|
description: 'Learn your first spell to siphon life from your foes.'
|
||||||
nextLevels:
|
nextLevels:
|
||||||
continue: 'bonemender'
|
continue: 'bonemender'
|
||||||
disabled: not me.isAdmin()
|
|
||||||
x: 65
|
x: 65
|
||||||
y: 48
|
y: 48
|
||||||
}
|
}
|
||||||
|
@ -790,7 +785,6 @@ forest = [
|
||||||
description: 'Cast regeneration on allied soldiers to withstand a siege.'
|
description: 'Cast regeneration on allied soldiers to withstand a siege.'
|
||||||
nextLevels:
|
nextLevels:
|
||||||
continue: 'coinucopia'
|
continue: 'coinucopia'
|
||||||
disabled: not me.isAdmin()
|
|
||||||
x: 66
|
x: 66
|
||||||
y: 40
|
y: 40
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,37 +64,24 @@ module.exports = class HeroVictoryModal extends ModalView
|
||||||
thangType.project = ['original', 'rasterIcon', 'name', 'soundTriggers']
|
thangType.project = ['original', 'rasterIcon', 'name', 'soundTriggers']
|
||||||
@thangTypes[thangTypeOriginal] = @supermodel.loadModel(thangType, 'thang').model
|
@thangTypes[thangTypeOriginal] = @supermodel.loadModel(thangType, 'thang').model
|
||||||
|
|
||||||
if achievementIDs.length
|
@newEarnedAchievements = []
|
||||||
url = "/db/earned_achievement?view=get-by-achievement-ids&achievementIDs=#{achievementIDs.join(',')}"
|
for achievement in @achievements.models
|
||||||
earnedAchievements = new CocoCollection([], {
|
continue unless achievement.completed
|
||||||
url: url
|
ea = new EarnedAchievement({
|
||||||
model: EarnedAchievement
|
collection: achievement.get('collection')
|
||||||
|
triggeredBy: @session.id
|
||||||
|
achievement: achievement.id
|
||||||
})
|
})
|
||||||
earnedAchievements.sizeShouldBe = achievementIDs.length
|
ea.save()
|
||||||
res = @supermodel.loadCollection(earnedAchievements, 'earned_achievements')
|
@newEarnedAchievements.push ea
|
||||||
@earnedAchievements = res.model
|
@listenToOnce ea, 'sync', ->
|
||||||
@listenToOnce @earnedAchievements, 'sync', ->
|
if _.all((ea.id for ea in @newEarnedAchievements))
|
||||||
@newEarnedAchievements = []
|
@listenToOnce me, 'sync', ->
|
||||||
recorded = (earned.get('achievement') for earned in @earnedAchievements.length)
|
@readyToContinue = true
|
||||||
for achievement in @achievements.models
|
@updateSavingProgressStatus()
|
||||||
continue unless achievement.completed
|
me.fetch() unless me.loading
|
||||||
earnedObjects = []
|
|
||||||
if achievement.id not in recorded
|
@readyToContinue = true if not @achievements.models.length
|
||||||
ea = new EarnedAchievement({
|
|
||||||
collection: achievement.get('collection')
|
|
||||||
triggeredBy: @session.id
|
|
||||||
achievement: achievement.id
|
|
||||||
})
|
|
||||||
ea.save()
|
|
||||||
@newEarnedAchievements.push ea
|
|
||||||
@listenToOnce ea, 'sync', ->
|
|
||||||
if _.all((ea.id for ea in @newEarnedAchievements))
|
|
||||||
@listenToOnce me, 'sync', ->
|
|
||||||
@readyToContinue = true
|
|
||||||
@updateSavingProgressStatus()
|
|
||||||
me.fetch() unless me.loading
|
|
||||||
else
|
|
||||||
@readyToContinue = true
|
|
||||||
|
|
||||||
getRenderData: ->
|
getRenderData: ->
|
||||||
c = super()
|
c = super()
|
||||||
|
|
|
@ -3,6 +3,7 @@ template = require 'templates/play/level/tome/spell_palette_entry'
|
||||||
{me} = require 'lib/auth'
|
{me} = require 'lib/auth'
|
||||||
filters = require 'lib/image_filter'
|
filters = require 'lib/image_filter'
|
||||||
DocFormatter = require './DocFormatter'
|
DocFormatter = require './DocFormatter'
|
||||||
|
SpellView = require 'views/play/level/tome/SpellView'
|
||||||
|
|
||||||
module.exports = class SpellPaletteEntryView extends CocoView
|
module.exports = class SpellPaletteEntryView extends CocoView
|
||||||
tagName: 'div' # Could also try <code> instead of <div>, but would need to adjust colors
|
tagName: 'div' # Could also try <code> instead of <div>, but would need to adjust colors
|
||||||
|
@ -28,6 +29,7 @@ module.exports = class SpellPaletteEntryView extends CocoView
|
||||||
@docFormatter = new DocFormatter options
|
@docFormatter = new DocFormatter options
|
||||||
@doc = @docFormatter.doc
|
@doc = @docFormatter.doc
|
||||||
@doc.initialHTML = @docFormatter.formatPopover()
|
@doc.initialHTML = @docFormatter.formatPopover()
|
||||||
|
@aceEditors = []
|
||||||
|
|
||||||
getRenderData: ->
|
getRenderData: ->
|
||||||
c = super()
|
c = super()
|
||||||
|
@ -52,6 +54,31 @@ module.exports = class SpellPaletteEntryView extends CocoView
|
||||||
Backbone.Mediator.publish 'audio-player:play-sound', trigger: "spell-palette-entry-open-#{soundIndex}", volume: 0.75
|
Backbone.Mediator.publish 'audio-player:play-sound', trigger: "spell-palette-entry-open-#{soundIndex}", volume: 0.75
|
||||||
popover = @$el.data('bs.popover')
|
popover = @$el.data('bs.popover')
|
||||||
popover?.$tip?.i18n()
|
popover?.$tip?.i18n()
|
||||||
|
codeLanguage = @options.language
|
||||||
|
oldEditor.destroy() for oldEditor in @aceEditors
|
||||||
|
@aceEditors = []
|
||||||
|
aceEditors = @aceEditors
|
||||||
|
popover?.$tip?.find('.docs-ace').each ->
|
||||||
|
contents = $(@).text()
|
||||||
|
editor = ace.edit @
|
||||||
|
editor.setOptions maxLines: Infinity
|
||||||
|
editor.setReadOnly true
|
||||||
|
editor.setTheme 'ace/theme/textmate'
|
||||||
|
editor.setShowPrintMargin false
|
||||||
|
editor.setShowFoldWidgets false
|
||||||
|
editor.setHighlightActiveLine false
|
||||||
|
editor.setHighlightActiveLine false
|
||||||
|
editor.setBehavioursEnabled false
|
||||||
|
editor.renderer.setShowGutter false
|
||||||
|
editor.setValue contents
|
||||||
|
editor.clearSelection()
|
||||||
|
session = editor.getSession()
|
||||||
|
session.setUseWorker false
|
||||||
|
session.setMode SpellView.editModes[codeLanguage]
|
||||||
|
session.setWrapLimitRange null
|
||||||
|
session.setUseWrapMode true
|
||||||
|
session.setNewLineMode 'unix'
|
||||||
|
aceEditors.push editor
|
||||||
|
|
||||||
onMouseEnter: (e) ->
|
onMouseEnter: (e) ->
|
||||||
# Make sure the doc has the updated Thang so it can regenerate its prop value
|
# Make sure the doc has the updated Thang so it can regenerate its prop value
|
||||||
|
@ -121,4 +148,5 @@ module.exports = class SpellPaletteEntryView extends CocoView
|
||||||
@togglePinned() if @popoverPinned
|
@togglePinned() if @popoverPinned
|
||||||
@$el.popover 'destroy'
|
@$el.popover 'destroy'
|
||||||
@$el.off()
|
@$el.off()
|
||||||
|
oldEditor.destroy() for oldEditor in @aceEditors
|
||||||
super()
|
super()
|
||||||
|
|
|
@ -20,7 +20,7 @@ module.exports = class SpellView extends CocoView
|
||||||
eventsSuppressed: true
|
eventsSuppressed: true
|
||||||
writable: true
|
writable: true
|
||||||
|
|
||||||
editModes:
|
@editModes:
|
||||||
'javascript': 'ace/mode/javascript'
|
'javascript': 'ace/mode/javascript'
|
||||||
'coffeescript': 'ace/mode/coffee'
|
'coffeescript': 'ace/mode/coffee'
|
||||||
'python': 'ace/mode/python'
|
'python': 'ace/mode/python'
|
||||||
|
@ -91,7 +91,7 @@ module.exports = class SpellView extends CocoView
|
||||||
@aceSession = @ace.getSession()
|
@aceSession = @ace.getSession()
|
||||||
@aceDoc = @aceSession.getDocument()
|
@aceDoc = @aceSession.getDocument()
|
||||||
@aceSession.setUseWorker false
|
@aceSession.setUseWorker false
|
||||||
@aceSession.setMode @editModes[@spell.language]
|
@aceSession.setMode SpellView.editModes[@spell.language]
|
||||||
@aceSession.setWrapLimitRange null
|
@aceSession.setWrapLimitRange null
|
||||||
@aceSession.setUseWrapMode true
|
@aceSession.setUseWrapMode true
|
||||||
@aceSession.setNewLineMode 'unix'
|
@aceSession.setNewLineMode 'unix'
|
||||||
|
@ -324,7 +324,7 @@ module.exports = class SpellView extends CocoView
|
||||||
|
|
||||||
# window.zatannaInstance = @zatanna
|
# window.zatannaInstance = @zatanna
|
||||||
# window.snippetEntries = snippetEntries
|
# window.snippetEntries = snippetEntries
|
||||||
lang = @editModes[e.language].substr 'ace/mode/'.length
|
lang = SpellView.editModes[e.language].substr 'ace/mode/'.length
|
||||||
@zatanna.addSnippets snippetEntries, lang
|
@zatanna.addSnippets snippetEntries, lang
|
||||||
|
|
||||||
onMultiplayerChanged: ->
|
onMultiplayerChanged: ->
|
||||||
|
@ -904,8 +904,8 @@ module.exports = class SpellView extends CocoView
|
||||||
|
|
||||||
onChangeLanguage: (e) ->
|
onChangeLanguage: (e) ->
|
||||||
return unless @spell.canWrite()
|
return unless @spell.canWrite()
|
||||||
@aceSession.setMode @editModes[e.language]
|
@aceSession.setMode SpellView.editModes[e.language]
|
||||||
@zatanna?.set 'language', @editModes[e.language].substr('ace/mode/')
|
@zatanna?.set 'language', SpellView.editModes[e.language].substr('ace/mode/')
|
||||||
wasDefault = @getSource() is @spell.originalSource
|
wasDefault = @getSource() is @spell.originalSource
|
||||||
@spell.setLanguage e.language
|
@spell.setLanguage e.language
|
||||||
@reloadCode true if wasDefault
|
@reloadCode true if wasDefault
|
||||||
|
|
|
@ -246,6 +246,7 @@ module.exports = class PlayHeroesModal extends ModalView
|
||||||
heroEntry = @$el.find(".hero-item[data-hero-id='#{@visibleHero.get('original')}']")
|
heroEntry = @$el.find(".hero-item[data-hero-id='#{@visibleHero.get('original')}']")
|
||||||
heroEntry.find('.hero-status-value').attr('data-i18n', 'play.available').i18n()
|
heroEntry.find('.hero-status-value').attr('data-i18n', 'play.available').i18n()
|
||||||
heroEntry.removeClass 'locked purchasable'
|
heroEntry.removeClass 'locked purchasable'
|
||||||
|
@selectedHero = @visibleHero
|
||||||
@rerenderFooter()
|
@rerenderFooter()
|
||||||
|
|
||||||
Backbone.Mediator.publish 'store:hero-purchased', hero: @visibleHero, heroSlug: @visibleHero.get('slug')
|
Backbone.Mediator.publish 'store:hero-purchased', hero: @visibleHero, heroSlug: @visibleHero.get('slug')
|
||||||
|
|
|
@ -61,19 +61,45 @@ class EarnedAchievementHandler extends Handler
|
||||||
EarnedAchievement.findOne q, (err, earned) -> callback(err, earned)
|
EarnedAchievement.findOne q, (err, earned) -> callback(err, earned)
|
||||||
}, (err, { achievement, trigger, earned } ) =>
|
}, (err, { achievement, trigger, earned } ) =>
|
||||||
return @sendDatabaseError(res, err) if err
|
return @sendDatabaseError(res, err) if err
|
||||||
if earned
|
|
||||||
return @sendSuccess(res, earned.toObject())
|
|
||||||
if not achievement
|
if not achievement
|
||||||
return @sendNotFoundError(res, 'Could not find achievement.')
|
return @sendNotFoundError(res, 'Could not find achievement.')
|
||||||
if not trigger
|
else if not trigger
|
||||||
return @sendNotFoundError(res, 'Could not find trigger.')
|
return @sendNotFoundError(res, 'Could not find trigger.')
|
||||||
if achievement.get('proportionalTo')
|
else if earned
|
||||||
|
achievementEarned = achievement.get('rewards')
|
||||||
|
actuallyEarned = earned.get('earnedRewards')
|
||||||
|
if not _.isEqual(achievementEarned, actuallyEarned)
|
||||||
|
earned.set('earnedRewards', achievementEarned)
|
||||||
|
earned.save((err) =>
|
||||||
|
return @sendDatabaseError(res, err) if err
|
||||||
|
@upsertNonNumericRewards(req.user, achievement, (err) =>
|
||||||
|
return @sendDatabaseError(res, err) if err
|
||||||
|
return @sendSuccess(res, earned.toObject())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else
|
||||||
|
@upsertNonNumericRewards(req.user, achievement, (err) =>
|
||||||
|
return @sendDatabaseError(res, err) if err
|
||||||
|
return @sendSuccess(res, earned.toObject())
|
||||||
|
)
|
||||||
|
else if achievement.get('proportionalTo')
|
||||||
return @sendBadInputError(res, 'Cannot currently do this to repeatable docs...')
|
return @sendBadInputError(res, 'Cannot currently do this to repeatable docs...')
|
||||||
EarnedAchievement.createForAchievement(achievement, trigger, null, (earnedAchievementDoc) =>
|
else
|
||||||
@sendCreated(res, earnedAchievementDoc.toObject())
|
EarnedAchievement.createForAchievement(achievement, trigger, null, (earnedAchievementDoc) =>
|
||||||
)
|
@sendCreated(res, earnedAchievementDoc.toObject())
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
upsertNonNumericRewards: (user, achievement, done) ->
|
||||||
|
update = {}
|
||||||
|
for rewardType, rewards of achievement.get('rewards') ? {}
|
||||||
|
continue if rewardType is 'gems'
|
||||||
|
if rewards.length
|
||||||
|
update.$addToSet ?= {}
|
||||||
|
update.$addToSet["earned.#{rewardType}"] = $each: rewards
|
||||||
|
User.update {_id: user._id}, update, {}, (err, count) ->
|
||||||
|
log.error err if err?
|
||||||
|
done?(err)
|
||||||
|
|
||||||
getByAchievementIDs: (req, res) ->
|
getByAchievementIDs: (req, res) ->
|
||||||
query = { user: req.user._id+''}
|
query = { user: req.user._id+''}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue